Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp
39644 views
//===-- NativeProcessFreeBSD.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 "NativeProcessFreeBSD.h"910// clang-format off11#include <sys/types.h>12#include <sys/ptrace.h>13#include <sys/sysctl.h>14#include <sys/user.h>15#include <sys/wait.h>16#include <machine/elf.h>17// clang-format on1819#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"20#include "lldb/Host/HostProcess.h"21#include "lldb/Host/posix/ProcessLauncherPosixFork.h"22#include "lldb/Target/Process.h"23#include "lldb/Utility/State.h"24#include "llvm/Support/Errno.h"2526using namespace lldb;27using namespace lldb_private;28using namespace lldb_private::process_freebsd;29using namespace llvm;3031// Simple helper function to ensure flags are enabled on the given file32// descriptor.33static Status EnsureFDFlags(int fd, int flags) {34Status error;3536int status = fcntl(fd, F_GETFL);37if (status == -1) {38error.SetErrorToErrno();39return error;40}4142if (fcntl(fd, F_SETFL, status | flags) == -1) {43error.SetErrorToErrno();44return error;45}4647return error;48}4950static Status CanTrace() {51int proc_debug, ret;52size_t len = sizeof(proc_debug);53ret = ::sysctlbyname("security.bsd.unprivileged_proc_debug", &proc_debug,54&len, nullptr, 0);55if (ret != 0)56return Status("sysctlbyname() security.bsd.unprivileged_proc_debug failed");5758if (proc_debug < 1)59return Status(60"process debug disabled by security.bsd.unprivileged_proc_debug oid");6162return {};63}6465// Public Static Methods6667llvm::Expected<std::unique_ptr<NativeProcessProtocol>>68NativeProcessFreeBSD::Manager::Launch(ProcessLaunchInfo &launch_info,69NativeDelegate &native_delegate) {70Log *log = GetLog(POSIXLog::Process);71Status status;7273::pid_t pid = ProcessLauncherPosixFork()74.LaunchProcess(launch_info, status)75.GetProcessId();76LLDB_LOG(log, "pid = {0:x}", pid);77if (status.Fail()) {78LLDB_LOG(log, "failed to launch process: {0}", status);79auto error = CanTrace();80if (error.Fail())81return error.ToError();82return status.ToError();83}8485// Wait for the child process to trap on its call to execve.86int wstatus;87::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);88assert(wpid == pid);89UNUSED_IF_ASSERT_DISABLED(wpid);90if (!WIFSTOPPED(wstatus)) {91LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",92WaitStatus::Decode(wstatus));93return llvm::make_error<StringError>("Could not sync with inferior process",94llvm::inconvertibleErrorCode());95}96LLDB_LOG(log, "inferior started, now in stopped state");9798ProcessInstanceInfo Info;99if (!Host::GetProcessInfo(pid, Info)) {100return llvm::make_error<StringError>("Cannot get process architecture",101llvm::inconvertibleErrorCode());102}103104// Set the architecture to the exe architecture.105LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,106Info.GetArchitecture().GetArchitectureName());107108std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD(109pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,110Info.GetArchitecture(), m_mainloop));111112status = process_up->SetupTrace();113if (status.Fail())114return status.ToError();115116for (const auto &thread : process_up->m_threads)117static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP);118process_up->SetState(StateType::eStateStopped, false);119120return std::move(process_up);121}122123llvm::Expected<std::unique_ptr<NativeProcessProtocol>>124NativeProcessFreeBSD::Manager::Attach(125lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {126Log *log = GetLog(POSIXLog::Process);127LLDB_LOG(log, "pid = {0:x}", pid);128129// Retrieve the architecture for the running process.130ProcessInstanceInfo Info;131if (!Host::GetProcessInfo(pid, Info)) {132return llvm::make_error<StringError>("Cannot get process architecture",133llvm::inconvertibleErrorCode());134}135136std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD(137pid, -1, native_delegate, Info.GetArchitecture(), m_mainloop));138139Status status = process_up->Attach();140if (!status.Success())141return status.ToError();142143return std::move(process_up);144}145146NativeProcessFreeBSD::Extension147NativeProcessFreeBSD::Manager::GetSupportedExtensions() const {148return149#if defined(PT_COREDUMP)150Extension::savecore |151#endif152Extension::multiprocess | Extension::fork | Extension::vfork |153Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 |154Extension::siginfo_read;155}156157// Public Instance Methods158159NativeProcessFreeBSD::NativeProcessFreeBSD(::pid_t pid, int terminal_fd,160NativeDelegate &delegate,161const ArchSpec &arch,162MainLoop &mainloop)163: NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),164m_main_loop(mainloop) {165if (m_terminal_fd != -1) {166Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);167assert(status.Success());168}169170Status status;171m_sigchld_handle = mainloop.RegisterSignal(172SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);173assert(m_sigchld_handle && status.Success());174}175176// Handles all waitpid events from the inferior process.177void NativeProcessFreeBSD::MonitorCallback(lldb::pid_t pid, int signal) {178switch (signal) {179case SIGTRAP:180return MonitorSIGTRAP(pid);181case SIGSTOP:182return MonitorSIGSTOP(pid);183default:184return MonitorSignal(pid, signal);185}186}187188void NativeProcessFreeBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {189Log *log = GetLog(POSIXLog::Process);190191LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);192193/* Stop Tracking All Threads attached to Process */194m_threads.clear();195196SetExitStatus(status, true);197198// Notify delegate that our process has exited.199SetState(StateType::eStateExited, true);200}201202void NativeProcessFreeBSD::MonitorSIGSTOP(lldb::pid_t pid) {203/* Stop all Threads attached to Process */204for (const auto &thread : m_threads) {205static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP,206nullptr);207}208SetState(StateType::eStateStopped, true);209}210211void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {212Log *log = GetLog(POSIXLog::Process);213struct ptrace_lwpinfo info;214215const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));216if (siginfo_err.Fail()) {217LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);218return;219}220assert(info.pl_event == PL_EVENT_SIGNAL);221222LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, flags = {2:x}", pid,223info.pl_lwpid, info.pl_flags);224NativeThreadFreeBSD *thread = nullptr;225226if (info.pl_flags & (PL_FLAG_BORN | PL_FLAG_EXITED)) {227if (info.pl_flags & PL_FLAG_BORN) {228LLDB_LOG(log, "monitoring new thread, tid = {0}", info.pl_lwpid);229NativeThreadFreeBSD &t = AddThread(info.pl_lwpid);230231// Technically, the FreeBSD kernel copies the debug registers to new232// threads. However, there is a non-negligible delay between acquiring233// the DR values and reporting the new thread during which the user may234// establish a new watchpoint. In order to ensure that watchpoints235// established during this period are propagated to new threads,236// explicitly copy the DR value at the time the new thread is reported.237//238// See also: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=250954239240llvm::Error error = t.CopyWatchpointsFrom(241static_cast<NativeThreadFreeBSD &>(*GetCurrentThread()));242if (error) {243LLDB_LOG_ERROR(log, std::move(error),244"failed to copy watchpoints to new thread {1}: {0}",245info.pl_lwpid);246SetState(StateType::eStateInvalid);247return;248}249} else /*if (info.pl_flags & PL_FLAG_EXITED)*/ {250LLDB_LOG(log, "thread exited, tid = {0}", info.pl_lwpid);251RemoveThread(info.pl_lwpid);252}253254Status error =255PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);256if (error.Fail())257SetState(StateType::eStateInvalid);258return;259}260261if (info.pl_flags & PL_FLAG_EXEC) {262Status error = ReinitializeThreads();263if (error.Fail()) {264SetState(StateType::eStateInvalid);265return;266}267268// Let our delegate know we have just exec'd.269NotifyDidExec();270271for (const auto &thread : m_threads)272static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedByExec();273SetCurrentThreadID(m_threads.front()->GetID());274SetState(StateType::eStateStopped, true);275return;276}277278if (info.pl_lwpid > 0) {279for (const auto &t : m_threads) {280if (t->GetID() == static_cast<lldb::tid_t>(info.pl_lwpid))281thread = static_cast<NativeThreadFreeBSD *>(t.get());282static_cast<NativeThreadFreeBSD *>(t.get())->SetStoppedWithNoReason();283}284if (!thread)285LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid,286info.pl_lwpid);287}288289if (info.pl_flags & PL_FLAG_FORKED) {290assert(thread);291MonitorClone(info.pl_child_pid, info.pl_flags & PL_FLAG_VFORKED, *thread);292return;293}294295if (info.pl_flags & PL_FLAG_VFORK_DONE) {296assert(thread);297if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) {298thread->SetStoppedByVForkDone();299SetState(StateType::eStateStopped, true);300} else {301Status error =302PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);303if (error.Fail())304SetState(StateType::eStateInvalid);305}306return;307}308309if (info.pl_flags & PL_FLAG_SI) {310assert(info.pl_siginfo.si_signo == SIGTRAP);311LLDB_LOG(log, "SIGTRAP siginfo: si_code = {0}, pid = {1}",312info.pl_siginfo.si_code, info.pl_siginfo.si_pid);313314switch (info.pl_siginfo.si_code) {315case TRAP_BRKPT:316LLDB_LOG(log, "SIGTRAP/TRAP_BRKPT: si_addr: {0}",317info.pl_siginfo.si_addr);318319if (thread) {320auto thread_info =321m_threads_stepping_with_breakpoint.find(thread->GetID());322if (thread_info != m_threads_stepping_with_breakpoint.end()) {323thread->SetStoppedByTrace();324Status brkpt_error = RemoveBreakpoint(thread_info->second);325if (brkpt_error.Fail())326LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}",327thread_info->first, brkpt_error);328m_threads_stepping_with_breakpoint.erase(thread_info);329} else330thread->SetStoppedByBreakpoint();331FixupBreakpointPCAsNeeded(*thread);332SetCurrentThreadID(thread->GetID());333}334SetState(StateType::eStateStopped, true);335return;336case TRAP_TRACE:337LLDB_LOG(log, "SIGTRAP/TRAP_TRACE: si_addr: {0}",338info.pl_siginfo.si_addr);339340if (thread) {341auto ®ctx = static_cast<NativeRegisterContextFreeBSD &>(342thread->GetRegisterContext());343uint32_t wp_index = LLDB_INVALID_INDEX32;344Status error = regctx.GetWatchpointHitIndex(345wp_index, reinterpret_cast<uintptr_t>(info.pl_siginfo.si_addr));346if (error.Fail())347LLDB_LOG(log,348"received error while checking for watchpoint hits, pid = "349"{0}, LWP = {1}, error = {2}",350pid, info.pl_lwpid, error);351if (wp_index != LLDB_INVALID_INDEX32) {352regctx.ClearWatchpointHit(wp_index);353thread->SetStoppedByWatchpoint(wp_index);354SetCurrentThreadID(thread->GetID());355SetState(StateType::eStateStopped, true);356break;357}358359thread->SetStoppedByTrace();360SetCurrentThreadID(thread->GetID());361}362363SetState(StateType::eStateStopped, true);364return;365}366}367368// Either user-generated SIGTRAP or an unknown event that would369// otherwise leave the debugger hanging.370LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler");371MonitorSignal(pid, SIGTRAP);372}373374void NativeProcessFreeBSD::MonitorSignal(lldb::pid_t pid, int signal) {375Log *log = GetLog(POSIXLog::Process);376struct ptrace_lwpinfo info;377378const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));379if (siginfo_err.Fail()) {380LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);381return;382}383assert(info.pl_event == PL_EVENT_SIGNAL);384// TODO: do we need to handle !PL_FLAG_SI?385assert(info.pl_flags & PL_FLAG_SI);386assert(info.pl_siginfo.si_signo == signal);387388for (const auto &abs_thread : m_threads) {389NativeThreadFreeBSD &thread =390static_cast<NativeThreadFreeBSD &>(*abs_thread);391assert(info.pl_lwpid >= 0);392if (info.pl_lwpid == 0 ||393static_cast<lldb::tid_t>(info.pl_lwpid) == thread.GetID()) {394thread.SetStoppedBySignal(info.pl_siginfo.si_signo, &info.pl_siginfo);395SetCurrentThreadID(thread.GetID());396} else397thread.SetStoppedWithNoReason();398}399SetState(StateType::eStateStopped, true);400}401402Status NativeProcessFreeBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,403int data, int *result) {404Log *log = GetLog(POSIXLog::Ptrace);405Status error;406int ret;407408errno = 0;409ret =410ptrace(req, static_cast<::pid_t>(pid), static_cast<caddr_t>(addr), data);411412if (ret == -1) {413error = CanTrace();414if (error.Success())415error.SetErrorToErrno();416}417418if (result)419*result = ret;420421LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);422423if (error.Fail())424LLDB_LOG(log, "ptrace() failed: {0}", error);425426return error;427}428429llvm::Expected<llvm::ArrayRef<uint8_t>>430NativeProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {431static const uint8_t g_arm_opcode[] = {0xfe, 0xde, 0xff, 0xe7};432static const uint8_t g_thumb_opcode[] = {0x01, 0xde};433434switch (GetArchitecture().GetMachine()) {435case llvm::Triple::arm:436switch (size_hint) {437case 2:438return llvm::ArrayRef(g_thumb_opcode);439case 4:440return llvm::ArrayRef(g_arm_opcode);441default:442return llvm::createStringError(llvm::inconvertibleErrorCode(),443"Unrecognised trap opcode size hint!");444}445default:446return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint);447}448}449450Status NativeProcessFreeBSD::Resume(const ResumeActionList &resume_actions) {451Log *log = GetLog(POSIXLog::Process);452LLDB_LOG(log, "pid {0}", GetID());453454Status ret;455456int signal = 0;457for (const auto &abs_thread : m_threads) {458assert(abs_thread && "thread list should not contain NULL threads");459NativeThreadFreeBSD &thread =460static_cast<NativeThreadFreeBSD &>(*abs_thread);461462const ResumeAction *action =463resume_actions.GetActionForThread(thread.GetID(), true);464// we need to explicit issue suspend requests, so it is simpler to map it465// into proper action466ResumeAction suspend_action{thread.GetID(), eStateSuspended,467LLDB_INVALID_SIGNAL_NUMBER};468469if (action == nullptr) {470LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),471thread.GetID());472action = &suspend_action;473}474475LLDB_LOG(476log,477"processing resume action state {0} signal {1} for pid {2} tid {3}",478action->state, action->signal, GetID(), thread.GetID());479480switch (action->state) {481case eStateRunning:482ret = thread.Resume();483break;484case eStateStepping:485ret = thread.SingleStep();486break;487case eStateSuspended:488case eStateStopped:489if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)490return Status("Passing signal to suspended thread unsupported");491492ret = thread.Suspend();493break;494495default:496return Status(497"NativeProcessFreeBSD::%s (): unexpected state %s specified "498"for pid %" PRIu64 ", tid %" PRIu64,499__FUNCTION__, StateAsCString(action->state), GetID(), thread.GetID());500}501502if (!ret.Success())503return ret;504if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)505signal = action->signal;506}507508ret =509PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal);510if (ret.Success())511SetState(eStateRunning, true);512return ret;513}514515Status NativeProcessFreeBSD::Halt() {516Status error;517518// Do not try to stop a process that's already stopped, this may cause519// the SIGSTOP to get queued and stop the process again once resumed.520if (StateIsStoppedState(m_state, false))521return error;522if (kill(GetID(), SIGSTOP) != 0)523error.SetErrorToErrno();524return error;525}526527Status NativeProcessFreeBSD::Detach() {528Status error;529530// Stop monitoring the inferior.531m_sigchld_handle.reset();532533// Tell ptrace to detach from the process.534if (GetID() == LLDB_INVALID_PROCESS_ID)535return error;536537return PtraceWrapper(PT_DETACH, GetID());538}539540Status NativeProcessFreeBSD::Signal(int signo) {541Status error;542543if (kill(GetID(), signo))544error.SetErrorToErrno();545546return error;547}548549Status NativeProcessFreeBSD::Interrupt() { return Halt(); }550551Status NativeProcessFreeBSD::Kill() {552Log *log = GetLog(POSIXLog::Process);553LLDB_LOG(log, "pid {0}", GetID());554555Status error;556557switch (m_state) {558case StateType::eStateInvalid:559case StateType::eStateExited:560case StateType::eStateCrashed:561case StateType::eStateDetached:562case StateType::eStateUnloaded:563// Nothing to do - the process is already dead.564LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),565StateAsCString(m_state));566return error;567568case StateType::eStateConnected:569case StateType::eStateAttaching:570case StateType::eStateLaunching:571case StateType::eStateStopped:572case StateType::eStateRunning:573case StateType::eStateStepping:574case StateType::eStateSuspended:575// We can try to kill a process in these states.576break;577}578579return PtraceWrapper(PT_KILL, m_pid);580}581582Status NativeProcessFreeBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,583MemoryRegionInfo &range_info) {584585if (m_supports_mem_region == LazyBool::eLazyBoolNo) {586// We're done.587return Status("unsupported");588}589590Status error = PopulateMemoryRegionCache();591if (error.Fail()) {592return error;593}594595lldb::addr_t prev_base_address = 0;596// FIXME start by finding the last region that is <= target address using597// binary search. Data is sorted.598// There can be a ton of regions on pthreads apps with lots of threads.599for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();600++it) {601MemoryRegionInfo &proc_entry_info = it->first;602// Sanity check assumption that memory map entries are ascending.603assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&604"descending memory map entries detected, unexpected");605prev_base_address = proc_entry_info.GetRange().GetRangeBase();606UNUSED_IF_ASSERT_DISABLED(prev_base_address);607// If the target address comes before this entry, indicate distance to next608// region.609if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {610range_info.GetRange().SetRangeBase(load_addr);611range_info.GetRange().SetByteSize(612proc_entry_info.GetRange().GetRangeBase() - load_addr);613range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);614range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);615range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);616range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);617return error;618} else if (proc_entry_info.GetRange().Contains(load_addr)) {619// The target address is within the memory region we're processing here.620range_info = proc_entry_info;621return error;622}623// The target memory address comes somewhere after the region we just624// parsed.625}626// If we made it here, we didn't find an entry that contained the given627// address. Return the load_addr as start and the amount of bytes betwwen628// load address and the end of the memory as size.629range_info.GetRange().SetRangeBase(load_addr);630range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);631range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);632range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);633range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);634range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);635return error;636}637638Status NativeProcessFreeBSD::PopulateMemoryRegionCache() {639Log *log = GetLog(POSIXLog::Process);640// If our cache is empty, pull the latest. There should always be at least641// one memory region if memory region handling is supported.642if (!m_mem_region_cache.empty()) {643LLDB_LOG(log, "reusing {0} cached memory region entries",644m_mem_region_cache.size());645return Status();646}647648int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, static_cast<int>(m_pid)};649int ret;650size_t len;651652ret = ::sysctl(mib, 4, nullptr, &len, nullptr, 0);653if (ret != 0) {654m_supports_mem_region = LazyBool::eLazyBoolNo;655return Status("sysctl() for KERN_PROC_VMMAP failed");656}657658std::unique_ptr<WritableMemoryBuffer> buf =659llvm::WritableMemoryBuffer::getNewMemBuffer(len);660ret = ::sysctl(mib, 4, buf->getBufferStart(), &len, nullptr, 0);661if (ret != 0) {662m_supports_mem_region = LazyBool::eLazyBoolNo;663return Status("sysctl() for KERN_PROC_VMMAP failed");664}665666char *bp = buf->getBufferStart();667char *end = bp + len;668while (bp < end) {669auto *kv = reinterpret_cast<struct kinfo_vmentry *>(bp);670if (kv->kve_structsize == 0)671break;672bp += kv->kve_structsize;673674MemoryRegionInfo info;675info.Clear();676info.GetRange().SetRangeBase(kv->kve_start);677info.GetRange().SetRangeEnd(kv->kve_end);678info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);679680if (kv->kve_protection & VM_PROT_READ)681info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);682else683info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);684685if (kv->kve_protection & VM_PROT_WRITE)686info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);687else688info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);689690if (kv->kve_protection & VM_PROT_EXECUTE)691info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);692else693info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);694695if (kv->kve_path[0])696info.SetName(kv->kve_path);697698m_mem_region_cache.emplace_back(info,699FileSpec(info.GetName().GetCString()));700}701702if (m_mem_region_cache.empty()) {703// No entries after attempting to read them. This shouldn't happen. Assume704// we don't support map entries.705LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "706"for memory region metadata retrieval");707m_supports_mem_region = LazyBool::eLazyBoolNo;708return Status("not supported");709}710LLDB_LOG(log, "read {0} memory region entries from process {1}",711m_mem_region_cache.size(), GetID());712// We support memory retrieval, remember that.713m_supports_mem_region = LazyBool::eLazyBoolYes;714715return Status();716}717718size_t NativeProcessFreeBSD::UpdateThreads() { return m_threads.size(); }719720Status NativeProcessFreeBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,721bool hardware) {722if (hardware)723return SetHardwareBreakpoint(addr, size);724return SetSoftwareBreakpoint(addr, size);725}726727Status NativeProcessFreeBSD::GetLoadedModuleFileSpec(const char *module_path,728FileSpec &file_spec) {729Status error = PopulateMemoryRegionCache();730if (error.Fail()) {731auto status = CanTrace();732if (status.Fail())733return status;734return error;735}736737FileSpec module_file_spec(module_path);738FileSystem::Instance().Resolve(module_file_spec);739740file_spec.Clear();741for (const auto &it : m_mem_region_cache) {742if (it.second.GetFilename() == module_file_spec.GetFilename()) {743file_spec = it.second;744return Status();745}746}747return Status("Module file (%s) not found in process' memory map!",748module_file_spec.GetFilename().AsCString());749}750751Status752NativeProcessFreeBSD::GetFileLoadAddress(const llvm::StringRef &file_name,753lldb::addr_t &load_addr) {754load_addr = LLDB_INVALID_ADDRESS;755Status error = PopulateMemoryRegionCache();756if (error.Fail()) {757auto status = CanTrace();758if (status.Fail())759return status;760return error;761}762763FileSpec file(file_name);764for (const auto &it : m_mem_region_cache) {765if (it.second == file) {766load_addr = it.first.GetRange().GetRangeBase();767return Status();768}769}770return Status("No load address found for file %s.", file_name.str().c_str());771}772773void NativeProcessFreeBSD::SigchldHandler() {774Log *log = GetLog(POSIXLog::Process);775int status;776::pid_t wait_pid =777llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WNOHANG);778779if (wait_pid == 0)780return;781782if (wait_pid == -1) {783Status error(errno, eErrorTypePOSIX);784LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);785return;786}787788WaitStatus wait_status = WaitStatus::Decode(status);789bool exited = wait_status.type == WaitStatus::Exit ||790(wait_status.type == WaitStatus::Signal &&791wait_pid == static_cast<::pid_t>(GetID()));792793LLDB_LOG(log,794"waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",795GetID(), wait_pid, status, exited);796797if (exited)798MonitorExited(wait_pid, wait_status);799else {800assert(wait_status.type == WaitStatus::Stop);801MonitorCallback(wait_pid, wait_status.status);802}803}804805bool NativeProcessFreeBSD::HasThreadNoLock(lldb::tid_t thread_id) {806for (const auto &thread : m_threads) {807assert(thread && "thread list should not contain NULL threads");808if (thread->GetID() == thread_id) {809// We have this thread.810return true;811}812}813814// We don't have this thread.815return false;816}817818NativeThreadFreeBSD &NativeProcessFreeBSD::AddThread(lldb::tid_t thread_id) {819Log *log = GetLog(POSIXLog::Thread);820LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);821822assert(thread_id > 0);823assert(!HasThreadNoLock(thread_id) &&824"attempted to add a thread by id that already exists");825826// If this is the first thread, save it as the current thread827if (m_threads.empty())828SetCurrentThreadID(thread_id);829830m_threads.push_back(std::make_unique<NativeThreadFreeBSD>(*this, thread_id));831return static_cast<NativeThreadFreeBSD &>(*m_threads.back());832}833834void NativeProcessFreeBSD::RemoveThread(lldb::tid_t thread_id) {835Log *log = GetLog(POSIXLog::Thread);836LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);837838assert(thread_id > 0);839assert(HasThreadNoLock(thread_id) &&840"attempted to remove a thread that does not exist");841842for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {843if ((*it)->GetID() == thread_id) {844m_threads.erase(it);845break;846}847}848849if (GetCurrentThreadID() == thread_id)850SetCurrentThreadID(m_threads.front()->GetID());851}852853Status NativeProcessFreeBSD::Attach() {854// Attach to the requested process.855// An attach will cause the thread to stop with a SIGSTOP.856Status status = PtraceWrapper(PT_ATTACH, m_pid);857if (status.Fail())858return status;859860int wstatus;861// Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this862// point we should have a thread stopped if waitpid succeeds.863if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr, 0)) <8640)865return Status(errno, eErrorTypePOSIX);866867// Initialize threads and tracing status868// NB: this needs to be called before we set thread state869status = SetupTrace();870if (status.Fail())871return status;872873for (const auto &thread : m_threads)874static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP);875876// Let our process instance know the thread has stopped.877SetCurrentThreadID(m_threads.front()->GetID());878SetState(StateType::eStateStopped, false);879return Status();880}881882Status NativeProcessFreeBSD::ReadMemory(lldb::addr_t addr, void *buf,883size_t size, size_t &bytes_read) {884unsigned char *dst = static_cast<unsigned char *>(buf);885struct ptrace_io_desc io;886887Log *log = GetLog(POSIXLog::Memory);888LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);889890bytes_read = 0;891io.piod_op = PIOD_READ_D;892io.piod_len = size;893894do {895io.piod_offs = (void *)(addr + bytes_read);896io.piod_addr = dst + bytes_read;897898Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io);899if (error.Fail() || io.piod_len == 0)900return error;901902bytes_read += io.piod_len;903io.piod_len = size - bytes_read;904} while (bytes_read < size);905906return Status();907}908909Status NativeProcessFreeBSD::WriteMemory(lldb::addr_t addr, const void *buf,910size_t size, size_t &bytes_written) {911const unsigned char *src = static_cast<const unsigned char *>(buf);912Status error;913struct ptrace_io_desc io;914915Log *log = GetLog(POSIXLog::Memory);916LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);917918bytes_written = 0;919io.piod_op = PIOD_WRITE_D;920io.piod_len = size;921922do {923io.piod_addr =924const_cast<void *>(static_cast<const void *>(src + bytes_written));925io.piod_offs = (void *)(addr + bytes_written);926927Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io);928if (error.Fail() || io.piod_len == 0)929return error;930931bytes_written += io.piod_len;932io.piod_len = size - bytes_written;933} while (bytes_written < size);934935return error;936}937938llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>939NativeProcessFreeBSD::GetAuxvData() const {940int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_AUXV, static_cast<int>(GetID())};941size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo);942std::unique_ptr<WritableMemoryBuffer> buf =943llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);944945if (::sysctl(mib, 4, buf->getBufferStart(), &auxv_size, nullptr, 0) != 0)946return std::error_code(errno, std::generic_category());947948return buf;949}950951Status NativeProcessFreeBSD::SetupTrace() {952// Enable event reporting953int events;954Status status =955PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));956if (status.Fail())957return status;958events |= PTRACE_LWP | PTRACE_FORK | PTRACE_VFORK;959status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));960if (status.Fail())961return status;962963return ReinitializeThreads();964}965966Status NativeProcessFreeBSD::ReinitializeThreads() {967// Clear old threads968m_threads.clear();969970int num_lwps;971Status error = PtraceWrapper(PT_GETNUMLWPS, GetID(), nullptr, 0, &num_lwps);972if (error.Fail())973return error;974975std::vector<lwpid_t> lwp_ids;976lwp_ids.resize(num_lwps);977error = PtraceWrapper(PT_GETLWPLIST, GetID(), lwp_ids.data(),978lwp_ids.size() * sizeof(lwpid_t), &num_lwps);979if (error.Fail())980return error;981982// Reinitialize from scratch threads and register them in process983for (lwpid_t lwp : lwp_ids)984AddThread(lwp);985986return error;987}988989bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const {990return !m_arch.IsMIPS();991}992993void NativeProcessFreeBSD::MonitorClone(::pid_t child_pid, bool is_vfork,994NativeThreadFreeBSD &parent_thread) {995Log *log = GetLog(POSIXLog::Process);996LLDB_LOG(log, "fork, child_pid={0}", child_pid);997998int status;999::pid_t wait_pid =1000llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);1001if (wait_pid != child_pid) {1002LLDB_LOG(log,1003"waiting for pid {0} failed. Assuming the pid has "1004"disappeared in the meantime",1005child_pid);1006return;1007}1008if (WIFEXITED(status)) {1009LLDB_LOG(log,1010"waiting for pid {0} returned an 'exited' event. Not "1011"tracking it.",1012child_pid);1013return;1014}10151016struct ptrace_lwpinfo info;1017const auto siginfo_err = PtraceWrapper(PT_LWPINFO, child_pid, &info, sizeof(info));1018if (siginfo_err.Fail()) {1019LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);1020return;1021}1022assert(info.pl_event == PL_EVENT_SIGNAL);1023lldb::tid_t child_tid = info.pl_lwpid;10241025std::unique_ptr<NativeProcessFreeBSD> child_process{1026new NativeProcessFreeBSD(static_cast<::pid_t>(child_pid), m_terminal_fd,1027m_delegate, m_arch, m_main_loop)};1028if (!is_vfork)1029child_process->m_software_breakpoints = m_software_breakpoints;10301031Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork;1032if ((m_enabled_extensions & expected_ext) == expected_ext) {1033child_process->SetupTrace();1034for (const auto &thread : child_process->m_threads)1035static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP);1036child_process->SetState(StateType::eStateStopped, false);10371038m_delegate.NewSubprocess(this, std::move(child_process));1039if (is_vfork)1040parent_thread.SetStoppedByVFork(child_pid, child_tid);1041else1042parent_thread.SetStoppedByFork(child_pid, child_tid);1043SetState(StateType::eStateStopped, true);1044} else {1045child_process->Detach();1046Status pt_error =1047PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), 0);1048if (pt_error.Fail()) {1049LLDB_LOG_ERROR(log, pt_error.ToError(),1050"unable to resume parent process {1}: {0}", GetID());1051SetState(StateType::eStateInvalid);1052}1053}1054}10551056llvm::Expected<std::string>1057NativeProcessFreeBSD::SaveCore(llvm::StringRef path_hint) {1058#if defined(PT_COREDUMP)1059using namespace llvm::sys::fs;10601061llvm::SmallString<128> path{path_hint};1062Status error;1063struct ptrace_coredump pc = {};10641065// Try with the suggested path first. If there is no suggested path or it1066// failed to open, use a temporary file.1067if (path.empty() ||1068openFile(path, pc.pc_fd, CD_CreateNew, FA_Write, OF_None)) {1069if (std::error_code errc =1070createTemporaryFile("lldb", "core", pc.pc_fd, path))1071return llvm::createStringError(errc, "Unable to create a temporary file");1072}1073error = PtraceWrapper(PT_COREDUMP, GetID(), &pc, sizeof(pc));10741075std::error_code close_err = closeFile(pc.pc_fd);1076if (error.Fail())1077return error.ToError();1078if (close_err)1079return llvm::createStringError(1080close_err, "Unable to close the core dump after writing");1081return path.str().str();1082#else // !defined(PT_COREDUMP)1083return llvm::createStringError(1084llvm::inconvertibleErrorCode(),1085"PT_COREDUMP not supported in the FreeBSD version used to build LLDB");1086#endif1087}108810891090