18#include "llvm/Support/Errno.h"
24#include <sys/ptrace.h>
25#include <sys/sysctl.h>
27#include <uvm/uvm_prot.h>
42 int status = fcntl(fd, F_GETFL);
48 if (fcntl(fd, F_SETFL, status | flags) == -1) {
58llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
69 LLDB_LOG(log,
"failed to launch process: {0}", status);
75 ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
78 if (!WIFSTOPPED(wstatus)) {
79 LLDB_LOG(log,
"Could not sync with inferior process: wstatus={1}",
81 return llvm::createStringError(
"Could not sync with inferior process");
83 LLDB_LOG(log,
"inferior started, now in stopped state");
87 return llvm::createStringError(
"Cannot get process architecture");
91 LLDB_LOG(log,
"pid = {0:x}, detected architecture {1}", pid,
92 Info.GetArchitecture().GetArchitectureName());
98 status = process_up->SetupTrace();
102 for (
const auto &thread : process_up->m_threads)
106 return std::move(process_up);
109llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
118 return llvm::createStringError(
"Cannot get process architecture");
122 pid, -1, native_delegate, Info.GetArchitecture(),
m_mainloop));
124 Status status = process_up->Attach();
128 return std::move(process_up);
172 LLDB_LOG(log,
"got exit signal({0}) , pid = {1}", status, pid);
184 ptrace_siginfo_t info;
186 const auto siginfo_err =
190 if (siginfo_err.Success()) {
192 if (info.psi_siginfo.si_code == SI_USER &&
193 info.psi_siginfo.si_pid == ::getpid()) {
206 ptrace_siginfo_t info;
208 const auto siginfo_err =
212 if (siginfo_err.Fail()) {
213 LLDB_LOG(log,
"PT_GET_SIGINFO failed {0}", siginfo_err);
217 LLDB_LOG(log,
"got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid,
218 info.psi_lwpid, info.psi_siginfo.si_code);
221 if (info.psi_lwpid > 0) {
223 if (t->GetID() ==
static_cast<lldb::tid_t>(info.psi_lwpid)) {
230 LLDB_LOG(log,
"thread not found in m_threads, pid = {0}, LWP = {1}", pid,
234 switch (info.psi_siginfo.si_code) {
237 thread->SetStoppedByBreakpoint();
244 thread->SetStoppedByTrace();
271 if (pst.pe_report_event == PTRACE_VFORK_DONE) {
273 thread->SetStoppedByVForkDone();
277 PtraceWrapper(PT_CONTINUE, pid,
reinterpret_cast<void *
>(1), 0);
282 assert(pst.pe_report_event == PTRACE_FORK ||
283 pst.pe_report_event == PTRACE_VFORK);
284 MonitorClone(pst.pe_other_pid, pst.pe_report_event == PTRACE_VFORK,
297 switch (pst.pe_report_event) {
298 case PTRACE_LWP_CREATE: {
299 LLDB_LOG(log,
"monitoring new thread, pid = {0}, LWP = {1}", pid,
305 LLDB_LOG(log,
"failed to copy watchpoints to new thread {0}: {1}",
311 case PTRACE_LWP_EXIT:
312 LLDB_LOG(log,
"removing exited thread, pid = {0}, LWP = {1}", pid,
328 thread->GetRegisterContext());
331 wp_index, (uintptr_t)info.psi_siginfo.si_addr);
334 "received error while checking for watchpoint hits, pid = "
335 "{0}, LWP = {1}, error = {2}",
336 pid, info.psi_lwpid,
error);
338 thread->SetStoppedByWatchpoint(wp_index);
339 regctx.ClearWatchpointHit(wp_index);
344 thread->SetStoppedByTrace();
352 LLDB_LOG(log,
"unknown SIGTRAP, passing to generic handler");
358 ptrace_siginfo_t info;
360 const auto siginfo_err =
362 if (siginfo_err.Fail()) {
363 LLDB_LOG(log,
"PT_LWPINFO failed {0}", siginfo_err);
367 for (
const auto &abs_thread :
m_threads) {
369 assert(info.psi_lwpid >= 0);
370 if (info.psi_lwpid == 0 ||
371 static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID())
372 thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo);
374 thread.SetStoppedWithNoReason();
393 LLDB_LOG(log,
"kill({0}, SIGSTOP)", pid);
403 int data,
int *result) {
409 ret = ptrace(req,
static_cast<::
pid_t>(pid), addr, data);
417 LLDB_LOG(log,
"ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
426 const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads,
435 size_t signaled_threads = 0;
438 for (
const auto &thread : threads) {
439 assert(thread &&
"thread list should not contain NULL threads");
445 if (action->
signal != signal) {
448 "NetBSD does not support passing multiple signals "
452 signaled_lwp = thread->GetID();
458 if (signaled_threads == 0) {
459 ptrace_siginfo_t siginfo;
464 if (signaled_threads > 1 && signaled_threads < threads.size())
466 "NetBSD does not support passing signal to 1<i<all threads")
469 ptrace_siginfo_t siginfo;
470 siginfo.psi_siginfo.si_signo = signal;
471 siginfo.psi_siginfo.si_code = SI_USER;
472 siginfo.psi_siginfo.si_pid = getpid();
473 siginfo.psi_siginfo.si_uid = getuid();
474 if (signaled_threads == 1)
475 siginfo.psi_lwpid = signaled_lwp;
477 siginfo.psi_lwpid = 0;
487 Expected<ptrace_siginfo_t> siginfo =
490 return Status(siginfo.takeError());
492 for (
const auto &abs_thread :
m_threads) {
493 assert(abs_thread &&
"thread list should not contain NULL threads");
503 if (action ==
nullptr) {
504 LLDB_LOG(log,
"no action specified for pid {0} tid {1}",
GetID(),
506 action = &suspend_action;
511 "processing resume action state {0} signal {1} for pid {2} tid {3}",
514 switch (action->
state) {
516 ret = thread.Resume();
519 ret = thread.SingleStep();
525 "Passing signal to suspended thread unsupported");
527 ret = thread.Suspend();
532 "NativeProcessNetBSD::%s (): unexpected state %s specified "
533 "for pid %" PRIu64
", tid %" PRIu64,
547 signal = siginfo->psi_siginfo.si_signo;
575 if (kill(
GetID(), signo))
596 LLDB_LOG(log,
"ignored for PID {0} due to current state: {1}",
GetID(),
641 "descending memory map entries detected, unexpected");
657 range_info = proc_entry_info;
680 LLDB_LOG(log,
"reusing {0} cached memory region entries",
685 struct kinfo_vmentry *vm;
687 vm = kinfo_getvmmap(
GetID(), &count);
694 for (i = 0; i < count; i++) {
701 if (vm[i].kve_protection & VM_PROT_READ)
706 if (vm[i].kve_protection & VM_PROT_WRITE)
711 if (vm[i].kve_protection & VM_PROT_EXECUTE)
716 if (vm[i].kve_path[0])
727 LLDB_LOG(log,
"failed to find any vmmap entries, assuming no support "
728 "for memory region metadata retrieval");
734 LLDB_LOG(log,
"read {0} memory region entries from process {1}",
752 "NativeProcessNetBSD does not support hardware breakpoints");
763 FileSpec module_file_spec(module_path);
768 if (it.second.GetFilename() == module_file_spec.
GetFilename()) {
769 file_spec = it.second;
774 "Module file (%s) not found in process' memory map!",
787 if (it.second == file) {
788 load_addr = it.first.GetRange().GetRangeBase();
793 file_name.str().c_str());
799 ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid,
GetID(), &status,
805 if (wait_pid == -1) {
817 "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
818 GetID(), wait_pid, status, exited);
830 assert(thread &&
"thread list should not contain NULL threads");
831 if (thread->GetID() == thread_id) {
843 LLDB_LOG(log,
"pid {0} adding thread with tid {1}",
GetID(), thread_id);
845 assert(thread_id > 0);
847 "attempted to add a thread by id that already exists");
853 m_threads.push_back(std::make_unique<NativeThreadNetBSD>(*
this, thread_id));
859 LLDB_LOG(log,
"pid {0} removing thread with tid {1}",
GetID(), thread_id);
861 assert(thread_id > 0);
863 "attempted to remove a thread that does not exist");
866 if ((*it)->GetID() == thread_id) {
883 if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid,
m_pid,
nullptr,
903 size_t size,
size_t &bytes_read) {
904 unsigned char *dst =
static_cast<unsigned char *
>(buf);
905 struct ptrace_io_desc io;
908 LLDB_LOG(log,
"addr = {0}, buf = {1}, size = {2}", addr, buf, size);
911 io.piod_op = PIOD_READ_D;
915 io.piod_offs = (
void *)(addr + bytes_read);
916 io.piod_addr = dst + bytes_read;
919 if (
error.Fail() || io.piod_len == 0)
922 bytes_read += io.piod_len;
923 io.piod_len = size - bytes_read;
924 }
while (bytes_read < size);
930 size_t size,
size_t &bytes_written) {
931 const unsigned char *src =
static_cast<const unsigned char *
>(buf);
933 struct ptrace_io_desc io;
936 LLDB_LOG(log,
"addr = {0}, buf = {1}, size = {2}", addr, buf, size);
939 io.piod_op = PIOD_WRITE_D;
944 const_cast<void *
>(
static_cast<const void *
>(src + bytes_written));
945 io.piod_offs = (
void *)(addr + bytes_written);
948 if (
error.Fail() || io.piod_len == 0)
951 bytes_written += io.piod_len;
952 io.piod_len = size - bytes_written;
953 }
while (bytes_written < size);
958llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
967 size_t auxv_size = 100 *
sizeof(AuxInfo);
969 ErrorOr<std::unique_ptr<WritableMemoryBuffer>> buf =
970 llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);
972 struct ptrace_io_desc io;
973 io.piod_op = PIOD_READ_AUXV;
975 io.piod_addr =
static_cast<void *
>(buf.get()->getBufferStart());
976 io.piod_len = auxv_size;
981 return std::error_code(
error.GetError(), std::generic_category());
984 return std::error_code(ECANCELED, std::generic_category());
986 return std::move(buf);
991 ptrace_event_t events;
997 events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT | PTRACE_FORK |
998 PTRACE_VFORK | PTRACE_VFORK_DONE;
1012 struct ptrace_lwpstatus info = {};
1013 int op = PT_LWPNEXT;
1015 struct ptrace_lwpinfo info = {};
1016 int op = PT_LWPINFO;
1025 while (info.pl_lwpid != 0) {
1039 LLDB_LOG(log,
"clone, child_pid={0}", child_pid);
1043 llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);
1044 if (wait_pid != child_pid) {
1046 "waiting for pid {0} failed. Assuming the pid has "
1047 "disappeared in the meantime",
1051 if (WIFEXITED(status)) {
1053 "waiting for pid {0} returned an 'exited' event. Not "
1059 ptrace_siginfo_t info;
1060 const auto siginfo_err =
1061 PtraceWrapper(PT_GET_SIGINFO, child_pid, &info,
sizeof(info));
1062 if (siginfo_err.Fail()) {
1063 LLDB_LOG(log,
"PT_GET_SIGINFO failed {0}", siginfo_err);
1066 assert(info.psi_lwpid >= 0);
1069 std::unique_ptr<NativeProcessNetBSD> child_process{
1077 child_process->SetupTrace();
1078 for (
const auto &thread : child_process->m_threads)
1082 m_delegate.NewSubprocess(
this, std::move(child_process));
1089 child_process->Detach();
1092 if (pt_error.
Fail()) {
1094 "unable to resume parent process {1}: {0}",
GetID());
1100llvm::Expected<std::string>
1102 llvm::SmallString<128> path{path_hint};
1106 if (!path.empty()) {
1109 return path.str().str();
1114 if (std::error_code errc =
1115 llvm::sys::fs::createTemporaryFile(
"lldb",
"core", path))
1116 return llvm::createStringError(errc,
"Unable to create a temporary file");
1120 return error.ToError();
1121 return path.str().str();
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_LOG_ERROR(log, error,...)
static Status EnsureFDFlags(int fd, int flags)
static Status EnsureFDFlags(int fd, int flags)
static llvm::Expected< ptrace_siginfo_t > ComputeSignalInfo(const std::vector< std::unique_ptr< NativeThreadProtocol > > &threads, const ResumeActionList &resume_actions)
An architecture specification class.
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
const char * GetCString() const
Get the string value as a C string.
const ConstString & GetFilename() const
Filename string const get accessor.
void Clear()
Clears the object state.
static FileSystem & Instance()
void Resolve(llvm::SmallVectorImpl< char > &path, bool force_make_absolute=false)
Resolve path to make it canonical.
lldb::pid_t GetProcessId() const
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info)
SignalHandleUP RegisterSignal(int signo, const Callback &callback, Status &error)
void SetMapped(OptionalBool val)
ConstString GetName() const
void SetReadable(OptionalBool val)
void SetExecutable(OptionalBool val)
void SetName(const char *name)
void SetWritable(OptionalBool val)
Abstract class that extends NativeProcessProtocol with ELF specific logic.
void NotifyDidExec() override
Notify the delegate that an exec occurred.
lldb::pid_t GetID() const
Status SetSoftwareBreakpoint(lldb::addr_t addr, uint32_t size_hint)
void SetState(lldb::StateType state, bool notify_delegates=true)
NativeThreadProtocol * GetCurrentThread()
void SetCurrentThreadID(lldb::tid_t tid)
std::vector< std::unique_ptr< NativeThreadProtocol > > m_threads
virtual bool SetExitStatus(WaitStatus status, bool bNotifyStateChange)
NativeDelegate & m_delegate
void FixupBreakpointPCAsNeeded(NativeThreadProtocol &thread)
Extension
Extension flag constants, returned by Manager::GetSupportedExtensions() and passed to SetEnabledExten...
Extension m_enabled_extensions
std::unordered_map< lldb::addr_t, SoftwareBreakpoint > m_software_breakpoints
HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Status &error) override
int ReleasePrimaryFileDescriptor()
Release the primary file descriptor.
const ResumeAction * GetActionForThread(lldb::tid_t tid, bool default_ok) const
static Status FromErrno()
Set the current error to errno.
llvm::Error ToError() const
FIXME: Replace all uses with takeError() instead.
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
static Status FromErrorString(const char *str)
bool Fail() const
Test for error condition.
bool Success() const
Test for success condition.
llvm::Expected< std::unique_ptr< NativeProcessProtocol > > Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override
Attach to an existing process.
Extension GetSupportedExtensions() const override
Get the bitmask of extensions supported by this process plugin.
llvm::Expected< std::unique_ptr< NativeProcessProtocol > > Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate) override
Launch a process for debugging.
llvm::Expected< std::string > SaveCore(llvm::StringRef path_hint) override
Write a core dump (without crashing the program).
lldb::addr_t GetSharedLibraryInfoAddress() override
void MonitorClone(::pid_t child_pid, bool is_vfork, NativeThreadNetBSD &parent_thread)
Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) override
Status Interrupt() override
Tells a process to interrupt all operations as if by a Ctrl-C.
Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info) override
Status GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) override
MainLoop::SignalHandleUP m_sigchld_handle
Status GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) override
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > GetAuxvData() const override
bool HasThreadNoLock(lldb::tid_t thread_id)
void MonitorSIGTRAP(lldb::pid_t pid)
Status ReinitializeThreads()
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) override
Status PopulateMemoryRegionCache()
std::vector< std::pair< MemoryRegionInfo, FileSpec > > m_mem_region_cache
Status Resume(const ResumeActionList &resume_actions) override
NativeProcessNetBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate, const ArchSpec &arch, MainLoop &mainloop)
size_t UpdateThreads() override
void MonitorExited(lldb::pid_t pid, WaitStatus status)
void MonitorCallback(lldb::pid_t pid, int signal)
NativeThreadNetBSD & AddThread(lldb::tid_t thread_id)
Status SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override
LazyBool m_supports_mem_region
void MonitorSIGSTOP(lldb::pid_t pid)
static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr=nullptr, int data=0, int *result=nullptr)
void RemoveThread(lldb::tid_t thread_id)
Status Signal(int signo) override
Sends a process a UNIX signal signal.
static Status StopProcess(lldb::pid_t pid)
void MonitorSignal(lldb::pid_t pid, int signal)
void SetStoppedByFork(lldb::pid_t child_pid, lldb::tid_t child_tid)
void SetStoppedBySignal(uint32_t signo, const siginfo_t *info=nullptr)
void SetStoppedWithNoReason()
void SetStoppedByVFork(lldb::pid_t child_pid, lldb::tid_t child_tid)
llvm::Error CopyWatchpointsFrom(NativeThreadNetBSD &source)
#define LLDB_INVALID_SIGNAL_NUMBER
#define LLDB_INVALID_INDEX32
#define UNUSED_IF_ASSERT_DISABLED(x)
#define LLDB_INVALID_ADDRESS
#define LLDB_INVALID_PROCESS_ID
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
const char * StateAsCString(lldb::StateType state)
Converts a StateType to a C string.
@ eStateUnloaded
Process is object is valid, but not currently loaded.
@ eStateConnected
Process is connected to remote debug services, but not launched or attached to anything yet.
@ eStateDetached
Process has been detached and can't be examined.
@ eStateStopped
Process or thread is stopped and can be examined.
@ eStateSuspended
Process or thread is in a suspended state as far as the debugger is concerned while other processes o...
@ eStateRunning
Process or thread is running and can't be examined.
@ eStateLaunching
Process is in the process of launching.
@ eStateAttaching
Process is currently trying to attach.
@ eStateExited
Process has exited and can't be examined.
@ eStateStepping
Process or thread is in the process of stepping and can not be examined.
@ eStateCrashed
Process or thread has crashed and can be examined.
@ eErrorTypePOSIX
POSIX error codes.
bool Contains(BaseType r) const
BaseType GetRangeBase() const
void SetRangeEnd(BaseType end)
void SetRangeBase(BaseType b)
Set the start value for the range, and keep the same size.
void SetByteSize(SizeType s)
static WaitStatus Decode(int wstatus)