13#include <sys/ptrace.h>
14#include <sys/sysctl.h>
17#include <machine/elf.h>
25#include "llvm/Support/Errno.h"
37 int status = fcntl(fd, F_GETFL);
43 if (fcntl(fd, F_SETFL, status | flags) == -1) {
53 size_t len =
sizeof(proc_debug);
54 ret = ::sysctlbyname(
"security.bsd.unprivileged_proc_debug", &proc_debug,
58 "sysctlbyname() security.bsd.unprivileged_proc_debug failed");
62 "process debug disabled by security.bsd.unprivileged_proc_debug oid");
69llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
80 LLDB_LOG(log,
"failed to launch process: {0}", status);
83 return error.ToError();
89 ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
92 if (!WIFSTOPPED(wstatus)) {
93 LLDB_LOG(log,
"Could not sync with inferior process: wstatus={1}",
95 return llvm::createStringError(
"Could not sync with inferior process");
97 LLDB_LOG(log,
"inferior started, now in stopped state");
101 return llvm::createStringError(
"Cannot get process architecture");
105 LLDB_LOG(log,
"pid = {0:x}, detected architecture {1}", pid,
106 Info.GetArchitecture().GetArchitectureName());
112 status = process_up->SetupTrace();
116 for (
const auto &thread : process_up->m_threads)
120 return std::move(process_up);
123llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
132 return llvm::createStringError(
"Cannot get process architecture");
136 pid, -1, native_delegate, Info.GetArchitecture(),
m_mainloop));
138 Status status = process_up->Attach();
142 return std::move(process_up);
148#if defined(PT_COREDUMP)
190 LLDB_LOG(log,
"got exit signal({0}) , pid = {1}", status, pid);
212 struct ptrace_lwpinfo info;
214 const auto siginfo_err =
PtraceWrapper(PT_LWPINFO, pid, &info,
sizeof(info));
215 if (siginfo_err.Fail()) {
216 LLDB_LOG(log,
"PT_LWPINFO failed {0}", siginfo_err);
219 assert(info.pl_event == PL_EVENT_SIGNAL);
221 LLDB_LOG(log,
"got SIGTRAP, pid = {0}, lwpid = {1}, flags = {2:x}", pid,
222 info.pl_lwpid, info.pl_flags);
225 if (info.pl_flags & (PL_FLAG_BORN | PL_FLAG_EXITED)) {
226 if (info.pl_flags & PL_FLAG_BORN) {
227 LLDB_LOG(log,
"monitoring new thread, tid = {0}", info.pl_lwpid);
243 "failed to copy watchpoints to new thread {1}: {0}",
249 LLDB_LOG(log,
"thread exited, tid = {0}", info.pl_lwpid);
254 PtraceWrapper(PT_CONTINUE, pid,
reinterpret_cast<void *
>(1), 0);
260 if (info.pl_flags & PL_FLAG_EXEC) {
277 if (info.pl_lwpid > 0) {
279 if (t->GetID() ==
static_cast<lldb::tid_t>(info.pl_lwpid))
284 LLDB_LOG(log,
"thread not found in m_threads, pid = {0}, LWP = {1}", pid,
288 if (info.pl_flags & PL_FLAG_FORKED) {
290 MonitorClone(info.pl_child_pid, info.pl_flags & PL_FLAG_VFORKED, *thread);
294 if (info.pl_flags & PL_FLAG_VFORK_DONE) {
297 thread->SetStoppedByVForkDone();
301 PtraceWrapper(PT_CONTINUE, pid,
reinterpret_cast<void *
>(1), 0);
308 if (info.pl_flags & PL_FLAG_SI) {
309 assert(info.pl_siginfo.si_signo ==
SIGTRAP);
310 LLDB_LOG(log,
"SIGTRAP siginfo: si_code = {0}, pid = {1}",
311 info.pl_siginfo.si_code, info.pl_siginfo.si_pid);
313 switch (info.pl_siginfo.si_code) {
315 LLDB_LOG(log,
"SIGTRAP/TRAP_BRKPT: si_addr: {0}",
316 info.pl_siginfo.si_addr);
320 thread->GetRegisterContext());
324 llvm::is_contained(thread_info->second, regctx.GetPC())) {
325 thread->SetStoppedByTrace();
326 for (
auto &&bp_addr : thread_info->second) {
328 if (brkpt_error.
Fail())
329 LLDB_LOG(log,
"pid = {0} remove stepping breakpoint: {1}",
330 thread_info->first, brkpt_error);
334 thread->SetStoppedByBreakpoint();
341 LLDB_LOG(log,
"SIGTRAP/TRAP_TRACE: si_addr: {0}",
342 info.pl_siginfo.si_addr);
346 thread->GetRegisterContext());
349 wp_index,
reinterpret_cast<uintptr_t
>(info.pl_siginfo.si_addr));
352 "received error while checking for watchpoint hits, pid = "
353 "{0}, LWP = {1}, error = {2}",
354 pid, info.pl_lwpid,
error);
356 regctx.ClearWatchpointHit(wp_index);
357 thread->SetStoppedByWatchpoint(wp_index);
363 thread->SetStoppedByTrace();
374 LLDB_LOG(log,
"unknown SIGTRAP, passing to generic handler");
380 struct ptrace_lwpinfo info;
382 const auto siginfo_err =
PtraceWrapper(PT_LWPINFO, pid, &info,
sizeof(info));
383 if (siginfo_err.Fail()) {
384 LLDB_LOG(log,
"PT_LWPINFO failed {0}", siginfo_err);
387 assert(info.pl_event == PL_EVENT_SIGNAL);
389 assert(info.pl_flags & PL_FLAG_SI);
390 assert(info.pl_siginfo.si_signo == signal);
392 for (
const auto &abs_thread :
m_threads) {
395 assert(info.pl_lwpid >= 0);
396 if (info.pl_lwpid == 0 ||
397 static_cast<lldb::tid_t>(info.pl_lwpid) == thread.GetID()) {
398 thread.SetStoppedBySignal(info.pl_siginfo.si_signo, &info.pl_siginfo);
401 thread.SetStoppedWithNoReason();
407 int data,
int *result) {
414 ptrace(req,
static_cast<::
pid_t>(pid),
static_cast<caddr_t
>(addr), data);
425 LLDB_LOG(log,
"ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
433llvm::Expected<llvm::ArrayRef<uint8_t>>
435 static const uint8_t g_arm_opcode[] = {0xfe, 0xde, 0xff, 0xe7};
436 static const uint8_t g_thumb_opcode[] = {0x01, 0xde};
439 case llvm::Triple::arm:
442 return llvm::ArrayRef(g_thumb_opcode);
444 return llvm::ArrayRef(g_arm_opcode);
446 return llvm::createStringError(llvm::inconvertibleErrorCode(),
447 "Unrecognised trap opcode size hint!");
461 for (
const auto &abs_thread :
m_threads) {
462 assert(abs_thread &&
"thread list should not contain NULL threads");
473 if (action ==
nullptr) {
474 LLDB_LOG(log,
"no action specified for pid {0} tid {1}",
GetID(),
476 action = &suspend_action;
481 "processing resume action state {0} signal {1} for pid {2} tid {3}",
484 switch (action->
state) {
486 ret = thread.Resume();
489 ret = thread.SingleStep();
495 "Passing signal to suspended thread unsupported");
497 ret = thread.Suspend();
502 "NativeProcessFreeBSD::%s (): unexpected state %s specified "
503 "for pid %" PRIu64
", tid %" PRIu64,
548 if (kill(
GetID(), signo))
569 LLDB_LOG(log,
"ignored for PID {0} due to current state: {1}",
GetID(),
609 "descending memory map entries detected, unexpected");
625 range_info = proc_entry_info;
648 LLDB_LOG(log,
"reusing {0} cached memory region entries",
653 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP,
static_cast<int>(
m_pid)};
657 ret = ::sysctl(mib, 4,
nullptr, &len,
nullptr, 0);
663 std::unique_ptr<WritableMemoryBuffer> buf =
664 llvm::WritableMemoryBuffer::getNewMemBuffer(len);
665 ret = ::sysctl(mib, 4, buf->getBufferStart(), &len,
nullptr, 0);
671 char *bp = buf->getBufferStart();
672 char *end = bp + len;
674 auto *kv =
reinterpret_cast<struct kinfo_vmentry *
>(bp);
675 if (kv->kve_structsize == 0)
677 bp += kv->kve_structsize;
685 if (kv->kve_protection & VM_PROT_READ)
690 if (kv->kve_protection & VM_PROT_WRITE)
695 if (kv->kve_protection & VM_PROT_EXECUTE)
710 LLDB_LOG(log,
"failed to find any vmmap entries, assuming no support "
711 "for memory region metadata retrieval");
715 LLDB_LOG(log,
"read {0} memory region entries from process {1}",
742 FileSpec module_file_spec(module_path);
747 if (it.second.GetFilename() == module_file_spec.
GetFilename()) {
748 file_spec = it.second;
753 "Module file (%s) not found in process' memory map!",
771 if (it.second == file) {
772 load_addr = it.first.GetRange().GetRangeBase();
777 file_name.str().c_str());
784 llvm::sys::RetryAfterSignal(-1, waitpid,
GetID(), &status, WNOHANG);
789 if (wait_pid == -1) {
801 "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
802 GetID(), wait_pid, status, exited);
814 assert(thread &&
"thread list should not contain NULL threads");
815 if (thread->GetID() == thread_id) {
827 LLDB_LOG(log,
"pid {0} adding thread with tid {1}",
GetID(), thread_id);
829 assert(thread_id > 0);
831 "attempted to add a thread by id that already exists");
837 m_threads.push_back(std::make_unique<NativeThreadFreeBSD>(*
this, thread_id));
843 LLDB_LOG(log,
"pid {0} removing thread with tid {1}",
GetID(), thread_id);
845 assert(thread_id > 0);
847 "attempted to remove a thread that does not exist");
850 if ((*it)->GetID() == thread_id) {
870 if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid,
m_pid,
nullptr, 0)) <
890 size_t size,
size_t &bytes_read) {
891 unsigned char *dst =
static_cast<unsigned char *
>(buf);
892 struct ptrace_io_desc io;
895 LLDB_LOG(log,
"addr = {0}, buf = {1}, size = {2}", addr, buf, size);
898 io.piod_op = PIOD_READ_D;
902 io.piod_offs = (
void *)(addr + bytes_read);
903 io.piod_addr = dst + bytes_read;
906 if (
error.Fail() || io.piod_len == 0)
909 bytes_read += io.piod_len;
910 io.piod_len = size - bytes_read;
911 }
while (bytes_read < size);
917 size_t size,
size_t &bytes_written) {
918 const unsigned char *src =
static_cast<const unsigned char *
>(buf);
920 struct ptrace_io_desc io;
923 LLDB_LOG(log,
"addr = {0}, buf = {1}, size = {2}", addr, buf, size);
926 io.piod_op = PIOD_WRITE_D;
931 const_cast<void *
>(
static_cast<const void *
>(src + bytes_written));
932 io.piod_offs = (
void *)(addr + bytes_written);
935 if (
error.Fail() || io.piod_len == 0)
938 bytes_written += io.piod_len;
939 io.piod_len = size - bytes_written;
940 }
while (bytes_written < size);
945llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
947 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_AUXV,
static_cast<int>(
GetID())};
948 size_t auxv_size = AT_COUNT *
sizeof(Elf_Auxinfo);
949 std::unique_ptr<WritableMemoryBuffer> buf =
950 llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);
952 if (::sysctl(mib, 4, buf->getBufferStart(), &auxv_size,
nullptr, 0) != 0)
953 return std::error_code(errno, std::generic_category());
965 events |= PTRACE_LWP | PTRACE_FORK | PTRACE_VFORK;
982 std::vector<lwpid_t> lwp_ids;
983 lwp_ids.resize(num_lwps);
985 lwp_ids.size() *
sizeof(lwpid_t), &num_lwps);
990 for (lwpid_t lwp : lwp_ids)
999 LLDB_LOG(log,
"fork, child_pid={0}", child_pid);
1003 llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0);
1004 if (wait_pid != child_pid) {
1006 "waiting for pid {0} failed. Assuming the pid has "
1007 "disappeared in the meantime",
1011 if (WIFEXITED(status)) {
1013 "waiting for pid {0} returned an 'exited' event. Not "
1019 struct ptrace_lwpinfo info;
1020 const auto siginfo_err =
1022 if (siginfo_err.Fail()) {
1023 LLDB_LOG(log,
"PT_LWPINFO failed {0}", siginfo_err);
1026 assert(info.pl_event == PL_EVENT_SIGNAL);
1029 std::unique_ptr<NativeProcessFreeBSD> child_process{
1037 child_process->SetupTrace();
1038 for (
const auto &thread : child_process->m_threads)
1042 m_delegate.NewSubprocess(
this, std::move(child_process));
1049 child_process->Detach();
1052 if (pt_error.
Fail()) {
1054 "unable to resume parent process {1}: {0}",
GetID());
1060llvm::Expected<std::string>
1062#if defined(PT_COREDUMP)
1063 using namespace llvm::sys::fs;
1065 llvm::SmallString<128> path{path_hint};
1067 struct ptrace_coredump
pc = {};
1072 openFile(path,
pc.pc_fd, CD_CreateNew, FA_Write, OF_None)) {
1073 if (std::error_code errc =
1074 createTemporaryFile(
"lldb",
"core",
pc.pc_fd, path))
1075 return llvm::createStringError(errc,
"Unable to create a temporary file");
1079 std::error_code close_err = closeFile(
pc.pc_fd);
1081 return error.ToError();
1083 return llvm::createStringError(
1084 close_err,
"Unable to close the core dump after writing");
1085 return path.str().str();
1087 return llvm::createStringError(
1088 llvm::inconvertibleErrorCode(),
1089 "PT_COREDUMP not supported in the FreeBSD version used to build LLDB");
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)
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)
virtual Status RemoveBreakpoint(lldb::addr_t addr, bool hardware=false)
NativeDelegate & m_delegate
void FixupBreakpointPCAsNeeded(NativeThreadProtocol &thread)
lldb::tid_t GetCurrentThreadID() const
Extension
Extension flag constants, returned by Manager::GetSupportedExtensions() and passed to SetEnabledExten...
virtual Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size)
virtual llvm::Expected< llvm::ArrayRef< uint8_t > > GetSoftwareBreakpointTrapOpcode(size_t size_hint)
Extension m_enabled_extensions
std::unordered_map< lldb::addr_t, SoftwareBreakpoint > m_software_breakpoints
std::map< lldb::tid_t, std::vector< lldb::addr_t > > m_threads_stepping_with_breakpoint
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 > > Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate) override
Launch a process for debugging.
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.
NativeThreadFreeBSD & AddThread(lldb::tid_t thread_id)
void MonitorCallback(lldb::pid_t pid, int signal)
void RemoveThread(lldb::tid_t thread_id)
void MonitorSIGSTOP(lldb::pid_t pid)
Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info) override
void MonitorSignal(lldb::pid_t pid, int signal)
void MonitorSIGTRAP(lldb::pid_t pid)
MainLoop::SignalHandleUP m_sigchld_handle
Status Resume(const ResumeActionList &resume_actions) override
Status PopulateMemoryRegionCache()
llvm::Expected< std::string > SaveCore(llvm::StringRef path_hint) override
Write a core dump (without crashing the program).
Status GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) override
size_t UpdateThreads() override
LazyBool m_supports_mem_region
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > GetAuxvData() const override
const ArchSpec & GetArchitecture() const override
void MonitorClone(::pid_t child_pid, bool is_vfork, NativeThreadFreeBSD &parent_thread)
static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr=nullptr, int data=0, int *result=nullptr)
Status Interrupt() override
Tells a process to interrupt all operations as if by a Ctrl-C.
Status ReinitializeThreads()
Status Signal(int signo) override
Sends a process a UNIX signal signal.
Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) override
Status GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) override
llvm::Expected< llvm::ArrayRef< uint8_t > > GetSoftwareBreakpointTrapOpcode(size_t size_hint) override
void MonitorExited(lldb::pid_t pid, WaitStatus status)
NativeProcessFreeBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate, const ArchSpec &arch, MainLoop &mainloop)
bool HasThreadNoLock(lldb::tid_t thread_id)
std::vector< std::pair< MemoryRegionInfo, FileSpec > > m_mem_region_cache
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) override
Status SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override
llvm::Error CopyWatchpointsFrom(NativeThreadFreeBSD &source)
void SetStoppedWithNoReason()
void SetStoppedByVFork(lldb::pid_t child_pid, lldb::tid_t child_tid)
void SetStoppedByFork(lldb::pid_t child_pid, lldb::tid_t child_tid)
void SetStoppedBySignal(uint32_t signo, const siginfo_t *info=nullptr)
#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.
bool StateIsStoppedState(lldb::StateType state, bool must_exist)
Check if a state represents a state where the process or thread is stopped.
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)