Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
39648 views
//===-- NativeProcessNetBSD.cpp -------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "NativeProcessNetBSD.h"910#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"11#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"12#include "lldb/Host/HostProcess.h"13#include "lldb/Host/common/NativeRegisterContext.h"14#include "lldb/Host/posix/ProcessLauncherPosixFork.h"15#include "lldb/Target/Process.h"16#include "lldb/Utility/State.h"17#include "llvm/Support/Errno.h"1819// System includes - They have to be included after framework includes because20// they define some macros which collide with variable names in other modules21// clang-format off22#include <sys/types.h>23#include <sys/ptrace.h>24#include <sys/sysctl.h>25#include <sys/wait.h>26#include <uvm/uvm_prot.h>27#include <elf.h>28#include <util.h>29// clang-format on3031using namespace lldb;32using namespace lldb_private;33using namespace lldb_private::process_netbsd;34using namespace llvm;3536// Simple helper function to ensure flags are enabled on the given file37// descriptor.38static Status EnsureFDFlags(int fd, int flags) {39Status error;4041int status = fcntl(fd, F_GETFL);42if (status == -1) {43error.SetErrorToErrno();44return error;45}4647if (fcntl(fd, F_SETFL, status | flags) == -1) {48error.SetErrorToErrno();49return error;50}5152return error;53}5455// Public Static Methods5657llvm::Expected<std::unique_ptr<NativeProcessProtocol>>58NativeProcessNetBSD::Manager::Launch(ProcessLaunchInfo &launch_info,59NativeDelegate &native_delegate) {60Log *log = GetLog(POSIXLog::Process);6162Status status;63::pid_t pid = ProcessLauncherPosixFork()64.LaunchProcess(launch_info, status)65.GetProcessId();66LLDB_LOG(log, "pid = {0:x}", pid);67if (status.Fail()) {68LLDB_LOG(log, "failed to launch process: {0}", status);69return status.ToError();70}7172// Wait for the child process to trap on its call to execve.73int wstatus;74::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);75assert(wpid == pid);76(void)wpid;77if (!WIFSTOPPED(wstatus)) {78LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",79WaitStatus::Decode(wstatus));80return llvm::make_error<StringError>("Could not sync with inferior process",81llvm::inconvertibleErrorCode());82}83LLDB_LOG(log, "inferior started, now in stopped state");8485ProcessInstanceInfo Info;86if (!Host::GetProcessInfo(pid, Info)) {87return llvm::make_error<StringError>("Cannot get process architecture",88llvm::inconvertibleErrorCode());89}9091// Set the architecture to the exe architecture.92LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,93Info.GetArchitecture().GetArchitectureName());9495std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(96pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,97Info.GetArchitecture(), m_mainloop));9899status = process_up->SetupTrace();100if (status.Fail())101return status.ToError();102103for (const auto &thread : process_up->m_threads)104static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);105process_up->SetState(StateType::eStateStopped, false);106107return std::move(process_up);108}109110llvm::Expected<std::unique_ptr<NativeProcessProtocol>>111NativeProcessNetBSD::Manager::Attach(112lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {113Log *log = GetLog(POSIXLog::Process);114LLDB_LOG(log, "pid = {0:x}", pid);115116// Retrieve the architecture for the running process.117ProcessInstanceInfo Info;118if (!Host::GetProcessInfo(pid, Info)) {119return llvm::make_error<StringError>("Cannot get process architecture",120llvm::inconvertibleErrorCode());121}122123std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(124pid, -1, native_delegate, Info.GetArchitecture(), m_mainloop));125126Status status = process_up->Attach();127if (!status.Success())128return status.ToError();129130return std::move(process_up);131}132133NativeProcessNetBSD::Extension134NativeProcessNetBSD::Manager::GetSupportedExtensions() const {135return Extension::multiprocess | Extension::fork | Extension::vfork |136Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |137Extension::savecore;138}139140// Public Instance Methods141142NativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd,143NativeDelegate &delegate,144const ArchSpec &arch,145MainLoop &mainloop)146: NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),147m_main_loop(mainloop) {148if (m_terminal_fd != -1) {149Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);150assert(status.Success());151}152153Status status;154m_sigchld_handle = mainloop.RegisterSignal(155SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);156assert(m_sigchld_handle && status.Success());157}158159// Handles all waitpid events from the inferior process.160void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {161switch (signal) {162case SIGTRAP:163return MonitorSIGTRAP(pid);164case SIGSTOP:165return MonitorSIGSTOP(pid);166default:167return MonitorSignal(pid, signal);168}169}170171void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {172Log *log = GetLog(POSIXLog::Process);173174LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);175176/* Stop Tracking All Threads attached to Process */177m_threads.clear();178179SetExitStatus(status, true);180181// Notify delegate that our process has exited.182SetState(StateType::eStateExited, true);183}184185void NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) {186ptrace_siginfo_t info;187188const auto siginfo_err =189PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));190191// Get details on the signal raised.192if (siginfo_err.Success()) {193// Handle SIGSTOP from LLGS (LLDB GDB Server)194if (info.psi_siginfo.si_code == SI_USER &&195info.psi_siginfo.si_pid == ::getpid()) {196/* Stop Tracking all Threads attached to Process */197for (const auto &thread : m_threads) {198static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(199SIGSTOP, &info.psi_siginfo);200}201}202SetState(StateType::eStateStopped, true);203}204}205206void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {207Log *log = GetLog(POSIXLog::Process);208ptrace_siginfo_t info;209210const auto siginfo_err =211PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));212213// Get details on the signal raised.214if (siginfo_err.Fail()) {215LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);216return;217}218219LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid,220info.psi_lwpid, info.psi_siginfo.si_code);221NativeThreadNetBSD *thread = nullptr;222223if (info.psi_lwpid > 0) {224for (const auto &t : m_threads) {225if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) {226thread = static_cast<NativeThreadNetBSD *>(t.get());227break;228}229static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason();230}231if (!thread)232LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid,233info.psi_lwpid);234}235236switch (info.psi_siginfo.si_code) {237case TRAP_BRKPT:238if (thread) {239thread->SetStoppedByBreakpoint();240FixupBreakpointPCAsNeeded(*thread);241}242SetState(StateType::eStateStopped, true);243return;244case TRAP_TRACE:245if (thread)246thread->SetStoppedByTrace();247SetState(StateType::eStateStopped, true);248return;249case TRAP_EXEC: {250Status error = ReinitializeThreads();251if (error.Fail()) {252SetState(StateType::eStateInvalid);253return;254}255256// Let our delegate know we have just exec'd.257NotifyDidExec();258259for (const auto &thread : m_threads)260static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec();261SetState(StateType::eStateStopped, true);262return;263}264case TRAP_CHLD: {265ptrace_state_t pst;266Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));267if (error.Fail()) {268SetState(StateType::eStateInvalid);269return;270}271272assert(thread);273if (pst.pe_report_event == PTRACE_VFORK_DONE) {274if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) {275thread->SetStoppedByVForkDone();276SetState(StateType::eStateStopped, true);277} else {278Status error =279PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);280if (error.Fail())281SetState(StateType::eStateInvalid);282}283} else {284assert(pst.pe_report_event == PTRACE_FORK ||285pst.pe_report_event == PTRACE_VFORK);286MonitorClone(pst.pe_other_pid, pst.pe_report_event == PTRACE_VFORK,287*thread);288}289return;290}291case TRAP_LWP: {292ptrace_state_t pst;293Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));294if (error.Fail()) {295SetState(StateType::eStateInvalid);296return;297}298299switch (pst.pe_report_event) {300case PTRACE_LWP_CREATE: {301LLDB_LOG(log, "monitoring new thread, pid = {0}, LWP = {1}", pid,302pst.pe_lwp);303NativeThreadNetBSD &t = AddThread(pst.pe_lwp);304error = t.CopyWatchpointsFrom(305static_cast<NativeThreadNetBSD &>(*GetCurrentThread()));306if (error.Fail()) {307LLDB_LOG(log, "failed to copy watchpoints to new thread {0}: {1}",308pst.pe_lwp, error);309SetState(StateType::eStateInvalid);310return;311}312} break;313case PTRACE_LWP_EXIT:314LLDB_LOG(log, "removing exited thread, pid = {0}, LWP = {1}", pid,315pst.pe_lwp);316RemoveThread(pst.pe_lwp);317break;318}319320error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);321if (error.Fail())322SetState(StateType::eStateInvalid);323return;324}325case TRAP_DBREG: {326if (!thread)327break;328329auto ®ctx = static_cast<NativeRegisterContextNetBSD &>(330thread->GetRegisterContext());331uint32_t wp_index = LLDB_INVALID_INDEX32;332Status error = regctx.GetWatchpointHitIndex(333wp_index, (uintptr_t)info.psi_siginfo.si_addr);334if (error.Fail())335LLDB_LOG(log,336"received error while checking for watchpoint hits, pid = "337"{0}, LWP = {1}, error = {2}",338pid, info.psi_lwpid, error);339if (wp_index != LLDB_INVALID_INDEX32) {340thread->SetStoppedByWatchpoint(wp_index);341regctx.ClearWatchpointHit(wp_index);342SetState(StateType::eStateStopped, true);343return;344}345346thread->SetStoppedByTrace();347SetState(StateType::eStateStopped, true);348return;349}350}351352// Either user-generated SIGTRAP or an unknown event that would353// otherwise leave the debugger hanging.354LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler");355MonitorSignal(pid, SIGTRAP);356}357358void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {359Log *log = GetLog(POSIXLog::Process);360ptrace_siginfo_t info;361362const auto siginfo_err =363PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));364if (siginfo_err.Fail()) {365LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);366return;367}368369for (const auto &abs_thread : m_threads) {370NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);371assert(info.psi_lwpid >= 0);372if (info.psi_lwpid == 0 ||373static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID())374thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo);375else376thread.SetStoppedWithNoReason();377}378SetState(StateType::eStateStopped, true);379}380381Status NativeProcessNetBSD::StopProcess(lldb::pid_t pid) {382#ifdef PT_STOP383return PtraceWrapper(PT_STOP, pid);384#else385Log *log = GetLog(POSIXLog::Ptrace);386Status error;387int ret;388389errno = 0;390ret = kill(pid, SIGSTOP);391392if (ret == -1)393error.SetErrorToErrno();394395LLDB_LOG(log, "kill({0}, SIGSTOP)", pid);396397if (error.Fail())398LLDB_LOG(log, "kill() failed: {0}", error);399400return error;401#endif402}403404Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,405int data, int *result) {406Log *log = GetLog(POSIXLog::Ptrace);407Status error;408int ret;409410errno = 0;411ret = ptrace(req, static_cast<::pid_t>(pid), addr, data);412413if (ret == -1)414error.SetErrorToErrno();415416if (result)417*result = ret;418419LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);420421if (error.Fail())422LLDB_LOG(log, "ptrace() failed: {0}", error);423424return error;425}426427static llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo(428const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads,429const ResumeActionList &resume_actions) {430// We need to account for three possible scenarios:431// 1. no signal being sent.432// 2. a signal being sent to one thread.433// 3. a signal being sent to the whole process.434435// Count signaled threads. While at it, determine which signal is being sent436// and ensure there's only one.437size_t signaled_threads = 0;438int signal = LLDB_INVALID_SIGNAL_NUMBER;439lldb::tid_t signaled_lwp;440for (const auto &thread : threads) {441assert(thread && "thread list should not contain NULL threads");442const ResumeAction *action =443resume_actions.GetActionForThread(thread->GetID(), true);444if (action) {445if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) {446signaled_threads++;447if (action->signal != signal) {448if (signal != LLDB_INVALID_SIGNAL_NUMBER)449return Status("NetBSD does not support passing multiple signals "450"simultaneously")451.ToError();452signal = action->signal;453signaled_lwp = thread->GetID();454}455}456}457}458459if (signaled_threads == 0) {460ptrace_siginfo_t siginfo;461siginfo.psi_siginfo.si_signo = LLDB_INVALID_SIGNAL_NUMBER;462return siginfo;463}464465if (signaled_threads > 1 && signaled_threads < threads.size())466return Status("NetBSD does not support passing signal to 1<i<all threads")467.ToError();468469ptrace_siginfo_t siginfo;470siginfo.psi_siginfo.si_signo = signal;471siginfo.psi_siginfo.si_code = SI_USER;472siginfo.psi_siginfo.si_pid = getpid();473siginfo.psi_siginfo.si_uid = getuid();474if (signaled_threads == 1)475siginfo.psi_lwpid = signaled_lwp;476else // signal for the whole process477siginfo.psi_lwpid = 0;478return siginfo;479}480481Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {482Log *log = GetLog(POSIXLog::Process);483LLDB_LOG(log, "pid {0}", GetID());484485Status ret;486487Expected<ptrace_siginfo_t> siginfo =488ComputeSignalInfo(m_threads, resume_actions);489if (!siginfo)490return Status(siginfo.takeError());491492for (const auto &abs_thread : m_threads) {493assert(abs_thread && "thread list should not contain NULL threads");494NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);495496const ResumeAction *action =497resume_actions.GetActionForThread(thread.GetID(), true);498// we need to explicit issue suspend requests, so it is simpler to map it499// into proper action500ResumeAction suspend_action{thread.GetID(), eStateSuspended,501LLDB_INVALID_SIGNAL_NUMBER};502503if (action == nullptr) {504LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),505thread.GetID());506action = &suspend_action;507}508509LLDB_LOG(510log,511"processing resume action state {0} signal {1} for pid {2} tid {3}",512action->state, action->signal, GetID(), thread.GetID());513514switch (action->state) {515case eStateRunning:516ret = thread.Resume();517break;518case eStateStepping:519ret = thread.SingleStep();520break;521case eStateSuspended:522case eStateStopped:523if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)524return Status("Passing signal to suspended thread unsupported");525526ret = thread.Suspend();527break;528529default:530return Status("NativeProcessNetBSD::%s (): unexpected state %s specified "531"for pid %" PRIu64 ", tid %" PRIu64,532__FUNCTION__, StateAsCString(action->state), GetID(),533thread.GetID());534}535536if (!ret.Success())537return ret;538}539540int signal = 0;541if (siginfo->psi_siginfo.si_signo != LLDB_INVALID_SIGNAL_NUMBER) {542ret = PtraceWrapper(PT_SET_SIGINFO, GetID(), &siginfo.get(),543sizeof(*siginfo));544if (!ret.Success())545return ret;546signal = siginfo->psi_siginfo.si_signo;547}548549ret =550PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal);551if (ret.Success())552SetState(eStateRunning, true);553return ret;554}555556Status NativeProcessNetBSD::Halt() { return StopProcess(GetID()); }557558Status NativeProcessNetBSD::Detach() {559Status error;560561// Stop monitoring the inferior.562m_sigchld_handle.reset();563564// Tell ptrace to detach from the process.565if (GetID() == LLDB_INVALID_PROCESS_ID)566return error;567568return PtraceWrapper(PT_DETACH, GetID(), reinterpret_cast<void *>(1));569}570571Status NativeProcessNetBSD::Signal(int signo) {572Status error;573574if (kill(GetID(), signo))575error.SetErrorToErrno();576577return error;578}579580Status NativeProcessNetBSD::Interrupt() { return StopProcess(GetID()); }581582Status NativeProcessNetBSD::Kill() {583Log *log = GetLog(POSIXLog::Process);584LLDB_LOG(log, "pid {0}", GetID());585586Status error;587588switch (m_state) {589case StateType::eStateInvalid:590case StateType::eStateExited:591case StateType::eStateCrashed:592case StateType::eStateDetached:593case StateType::eStateUnloaded:594// Nothing to do - the process is already dead.595LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),596StateAsCString(m_state));597return error;598599case StateType::eStateConnected:600case StateType::eStateAttaching:601case StateType::eStateLaunching:602case StateType::eStateStopped:603case StateType::eStateRunning:604case StateType::eStateStepping:605case StateType::eStateSuspended:606// We can try to kill a process in these states.607break;608}609610if (kill(GetID(), SIGKILL) != 0) {611error.SetErrorToErrno();612return error;613}614615return error;616}617618Status NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,619MemoryRegionInfo &range_info) {620621if (m_supports_mem_region == LazyBool::eLazyBoolNo) {622// We're done.623return Status("unsupported");624}625626Status error = PopulateMemoryRegionCache();627if (error.Fail()) {628return error;629}630631lldb::addr_t prev_base_address = 0;632// FIXME start by finding the last region that is <= target address using633// binary search. Data is sorted.634// There can be a ton of regions on pthreads apps with lots of threads.635for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();636++it) {637MemoryRegionInfo &proc_entry_info = it->first;638// Sanity check assumption that memory map entries are ascending.639assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&640"descending memory map entries detected, unexpected");641prev_base_address = proc_entry_info.GetRange().GetRangeBase();642UNUSED_IF_ASSERT_DISABLED(prev_base_address);643// If the target address comes before this entry, indicate distance to next644// region.645if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {646range_info.GetRange().SetRangeBase(load_addr);647range_info.GetRange().SetByteSize(648proc_entry_info.GetRange().GetRangeBase() - load_addr);649range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);650range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);651range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);652range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);653return error;654} else if (proc_entry_info.GetRange().Contains(load_addr)) {655// The target address is within the memory region we're processing here.656range_info = proc_entry_info;657return error;658}659// The target memory address comes somewhere after the region we just660// parsed.661}662// If we made it here, we didn't find an entry that contained the given663// address. Return the load_addr as start and the amount of bytes betwwen664// load address and the end of the memory as size.665range_info.GetRange().SetRangeBase(load_addr);666range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);667range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);668range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);669range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);670range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);671return error;672}673674Status NativeProcessNetBSD::PopulateMemoryRegionCache() {675Log *log = GetLog(POSIXLog::Process);676// If our cache is empty, pull the latest. There should always be at least677// one memory region if memory region handling is supported.678if (!m_mem_region_cache.empty()) {679LLDB_LOG(log, "reusing {0} cached memory region entries",680m_mem_region_cache.size());681return Status();682}683684struct kinfo_vmentry *vm;685size_t count, i;686vm = kinfo_getvmmap(GetID(), &count);687if (vm == NULL) {688m_supports_mem_region = LazyBool::eLazyBoolNo;689Status error;690error.SetErrorString("not supported");691return error;692}693for (i = 0; i < count; i++) {694MemoryRegionInfo info;695info.Clear();696info.GetRange().SetRangeBase(vm[i].kve_start);697info.GetRange().SetRangeEnd(vm[i].kve_end);698info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);699700if (vm[i].kve_protection & VM_PROT_READ)701info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);702else703info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);704705if (vm[i].kve_protection & VM_PROT_WRITE)706info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);707else708info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);709710if (vm[i].kve_protection & VM_PROT_EXECUTE)711info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);712else713info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);714715if (vm[i].kve_path[0])716info.SetName(vm[i].kve_path);717718m_mem_region_cache.emplace_back(info,719FileSpec(info.GetName().GetCString()));720}721free(vm);722723if (m_mem_region_cache.empty()) {724// No entries after attempting to read them. This shouldn't happen. Assume725// we don't support map entries.726LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "727"for memory region metadata retrieval");728m_supports_mem_region = LazyBool::eLazyBoolNo;729Status error;730error.SetErrorString("not supported");731return error;732}733LLDB_LOG(log, "read {0} memory region entries from process {1}",734m_mem_region_cache.size(), GetID());735// We support memory retrieval, remember that.736m_supports_mem_region = LazyBool::eLazyBoolYes;737return Status();738}739740lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {741// punt on this for now742return LLDB_INVALID_ADDRESS;743}744745size_t NativeProcessNetBSD::UpdateThreads() { return m_threads.size(); }746747Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,748bool hardware) {749if (hardware)750return Status("NativeProcessNetBSD does not support hardware breakpoints");751else752return SetSoftwareBreakpoint(addr, size);753}754755Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,756FileSpec &file_spec) {757Status error = PopulateMemoryRegionCache();758if (error.Fail())759return error;760761FileSpec module_file_spec(module_path);762FileSystem::Instance().Resolve(module_file_spec);763764file_spec.Clear();765for (const auto &it : m_mem_region_cache) {766if (it.second.GetFilename() == module_file_spec.GetFilename()) {767file_spec = it.second;768return Status();769}770}771return Status("Module file (%s) not found in process' memory map!",772module_file_spec.GetFilename().AsCString());773}774775Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,776lldb::addr_t &load_addr) {777load_addr = LLDB_INVALID_ADDRESS;778Status error = PopulateMemoryRegionCache();779if (error.Fail())780return error;781782FileSpec file(file_name);783for (const auto &it : m_mem_region_cache) {784if (it.second == file) {785load_addr = it.first.GetRange().GetRangeBase();786return Status();787}788}789return Status("No load address found for file %s.", file_name.str().c_str());790}791792void NativeProcessNetBSD::SigchldHandler() {793Log *log = GetLog(POSIXLog::Process);794int status;795::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status,796WALLSIG | WNOHANG);797798if (wait_pid == 0)799return;800801if (wait_pid == -1) {802Status error(errno, eErrorTypePOSIX);803LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);804return;805}806807WaitStatus wait_status = WaitStatus::Decode(status);808bool exited = wait_status.type == WaitStatus::Exit ||809(wait_status.type == WaitStatus::Signal &&810wait_pid == static_cast<::pid_t>(GetID()));811812LLDB_LOG(log,813"waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",814GetID(), wait_pid, status, exited);815816if (exited)817MonitorExited(wait_pid, wait_status);818else {819assert(wait_status.type == WaitStatus::Stop);820MonitorCallback(wait_pid, wait_status.status);821}822}823824bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {825for (const auto &thread : m_threads) {826assert(thread && "thread list should not contain NULL threads");827if (thread->GetID() == thread_id) {828// We have this thread.829return true;830}831}832833// We don't have this thread.834return false;835}836837NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {838Log *log = GetLog(POSIXLog::Thread);839LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);840841assert(thread_id > 0);842assert(!HasThreadNoLock(thread_id) &&843"attempted to add a thread by id that already exists");844845// If this is the first thread, save it as the current thread846if (m_threads.empty())847SetCurrentThreadID(thread_id);848849m_threads.push_back(std::make_unique<NativeThreadNetBSD>(*this, thread_id));850return static_cast<NativeThreadNetBSD &>(*m_threads.back());851}852853void NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) {854Log *log = GetLog(POSIXLog::Thread);855LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);856857assert(thread_id > 0);858assert(HasThreadNoLock(thread_id) &&859"attempted to remove a thread that does not exist");860861for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {862if ((*it)->GetID() == thread_id) {863m_threads.erase(it);864break;865}866}867}868869Status NativeProcessNetBSD::Attach() {870// Attach to the requested process.871// An attach will cause the thread to stop with a SIGSTOP.872Status status = PtraceWrapper(PT_ATTACH, m_pid);873if (status.Fail())874return status;875876int wstatus;877// Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this878// point we should have a thread stopped if waitpid succeeds.879if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr,880WALLSIG)) < 0)881return Status(errno, eErrorTypePOSIX);882883// Initialize threads and tracing status884// NB: this needs to be called before we set thread state885status = SetupTrace();886if (status.Fail())887return status;888889for (const auto &thread : m_threads)890static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);891892// Let our process instance know the thread has stopped.893SetCurrentThreadID(m_threads.front()->GetID());894SetState(StateType::eStateStopped, false);895return Status();896}897898Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf,899size_t size, size_t &bytes_read) {900unsigned char *dst = static_cast<unsigned char *>(buf);901struct ptrace_io_desc io;902903Log *log = GetLog(POSIXLog::Memory);904LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);905906bytes_read = 0;907io.piod_op = PIOD_READ_D;908io.piod_len = size;909910do {911io.piod_offs = (void *)(addr + bytes_read);912io.piod_addr = dst + bytes_read;913914Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);915if (error.Fail() || io.piod_len == 0)916return error;917918bytes_read += io.piod_len;919io.piod_len = size - bytes_read;920} while (bytes_read < size);921922return Status();923}924925Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf,926size_t size, size_t &bytes_written) {927const unsigned char *src = static_cast<const unsigned char *>(buf);928Status error;929struct ptrace_io_desc io;930931Log *log = GetLog(POSIXLog::Memory);932LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);933934bytes_written = 0;935io.piod_op = PIOD_WRITE_D;936io.piod_len = size;937938do {939io.piod_addr =940const_cast<void *>(static_cast<const void *>(src + bytes_written));941io.piod_offs = (void *)(addr + bytes_written);942943Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);944if (error.Fail() || io.piod_len == 0)945return error;946947bytes_written += io.piod_len;948io.piod_len = size - bytes_written;949} while (bytes_written < size);950951return error;952}953954llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>955NativeProcessNetBSD::GetAuxvData() const {956/*957* ELF_AUX_ENTRIES is currently restricted to kernel958* (<sys/exec_elf.h> r. 1.155 specifies 15)959*960* ptrace(2) returns the whole AUXV including extra fiels after AT_NULL this961* information isn't needed.962*/963size_t auxv_size = 100 * sizeof(AuxInfo);964965ErrorOr<std::unique_ptr<WritableMemoryBuffer>> buf =966llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);967968struct ptrace_io_desc io;969io.piod_op = PIOD_READ_AUXV;970io.piod_offs = 0;971io.piod_addr = static_cast<void *>(buf.get()->getBufferStart());972io.piod_len = auxv_size;973974Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);975976if (error.Fail())977return std::error_code(error.GetError(), std::generic_category());978979if (io.piod_len < 1)980return std::error_code(ECANCELED, std::generic_category());981982return std::move(buf);983}984985Status NativeProcessNetBSD::SetupTrace() {986// Enable event reporting987ptrace_event_t events;988Status status =989PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));990if (status.Fail())991return status;992// TODO: PTRACE_POSIX_SPAWN?993events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT | PTRACE_FORK |994PTRACE_VFORK | PTRACE_VFORK_DONE;995status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));996if (status.Fail())997return status;998999return ReinitializeThreads();1000}10011002Status NativeProcessNetBSD::ReinitializeThreads() {1003// Clear old threads1004m_threads.clear();10051006// Initialize new thread1007#ifdef PT_LWPSTATUS1008struct ptrace_lwpstatus info = {};1009int op = PT_LWPNEXT;1010#else1011struct ptrace_lwpinfo info = {};1012int op = PT_LWPINFO;1013#endif10141015Status error = PtraceWrapper(op, GetID(), &info, sizeof(info));10161017if (error.Fail()) {1018return error;1019}1020// Reinitialize from scratch threads and register them in process1021while (info.pl_lwpid != 0) {1022AddThread(info.pl_lwpid);1023error = PtraceWrapper(op, GetID(), &info, sizeof(info));1024if (error.Fail()) {1025return error;1026}1027}10281029return error;1030}10311032void NativeProcessNetBSD::MonitorClone(::pid_t child_pid, bool is_vfork,1033NativeThreadNetBSD &parent_thread) {1034Log *log = GetLog(POSIXLog::Process);1035LLDB_LOG(log, "clone, child_pid={0}", child_pid);10361037int status;1038::pid_t wait_pid =1039llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);1040if (wait_pid != child_pid) {1041LLDB_LOG(log,1042"waiting for pid {0} failed. Assuming the pid has "1043"disappeared in the meantime",1044child_pid);1045return;1046}1047if (WIFEXITED(status)) {1048LLDB_LOG(log,1049"waiting for pid {0} returned an 'exited' event. Not "1050"tracking it.",1051child_pid);1052return;1053}10541055ptrace_siginfo_t info;1056const auto siginfo_err =1057PtraceWrapper(PT_GET_SIGINFO, child_pid, &info, sizeof(info));1058if (siginfo_err.Fail()) {1059LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);1060return;1061}1062assert(info.psi_lwpid >= 0);1063lldb::tid_t child_tid = info.psi_lwpid;10641065std::unique_ptr<NativeProcessNetBSD> child_process{1066new NativeProcessNetBSD(static_cast<::pid_t>(child_pid), m_terminal_fd,1067m_delegate, m_arch, m_main_loop)};1068if (!is_vfork)1069child_process->m_software_breakpoints = m_software_breakpoints;10701071Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork;1072if ((m_enabled_extensions & expected_ext) == expected_ext) {1073child_process->SetupTrace();1074for (const auto &thread : child_process->m_threads)1075static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);1076child_process->SetState(StateType::eStateStopped, false);10771078m_delegate.NewSubprocess(this, std::move(child_process));1079if (is_vfork)1080parent_thread.SetStoppedByVFork(child_pid, child_tid);1081else1082parent_thread.SetStoppedByFork(child_pid, child_tid);1083SetState(StateType::eStateStopped, true);1084} else {1085child_process->Detach();1086Status pt_error =1087PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 0);1088if (pt_error.Fail()) {1089LLDB_LOG_ERROR(log, std::move(pt_error.ToError()),1090"unable to resume parent process {1}: {0}", GetID());1091SetState(StateType::eStateInvalid);1092}1093}1094}10951096llvm::Expected<std::string>1097NativeProcessNetBSD::SaveCore(llvm::StringRef path_hint) {1098llvm::SmallString<128> path{path_hint};1099Status error;11001101// Try with the suggested path first.1102if (!path.empty()) {1103error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());1104if (!error.Fail())1105return path.str().str();11061107// If the request errored, fall back to a generic temporary file.1108}11091110if (std::error_code errc =1111llvm::sys::fs::createTemporaryFile("lldb", "core", path))1112return llvm::createStringError(errc, "Unable to create a temporary file");11131114error = PtraceWrapper(PT_DUMPCORE, GetID(), path.data(), path.size());1115if (error.Fail())1116return error.ToError();1117return path.str().str();1118}111911201121