diff options
Diffstat (limited to 'lldb/source/Plugins/Process')
31 files changed, 716 insertions, 622 deletions
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp index a62d3c1ba052..21c9ead0eca4 100644 --- a/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp @@ -54,7 +54,7 @@ llvm::Expected<std::unique_ptr<NativeProcessProtocol>> NativeProcessFreeBSD::Factory::Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, MainLoop &mainloop) const { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); Status status; ::pid_t pid = ProcessLauncherPosixFork() @@ -108,7 +108,7 @@ llvm::Expected<std::unique_ptr<NativeProcessProtocol>> NativeProcessFreeBSD::Factory::Attach( lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop) const { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); LLDB_LOG(log, "pid = {0:x}", pid); // Retrieve the architecture for the running process. @@ -135,7 +135,8 @@ NativeProcessFreeBSD::Factory::GetSupportedExtensions() const { Extension::savecore | #endif Extension::multiprocess | Extension::fork | Extension::vfork | - Extension::pass_signals | Extension::auxv | Extension::libraries_svr4; + Extension::pass_signals | Extension::auxv | Extension::libraries_svr4 | + Extension::siginfo_read; } // Public Instance Methods @@ -170,7 +171,7 @@ void NativeProcessFreeBSD::MonitorCallback(lldb::pid_t pid, int signal) { } void NativeProcessFreeBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid); @@ -193,7 +194,7 @@ void NativeProcessFreeBSD::MonitorSIGSTOP(lldb::pid_t pid) { } void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); struct ptrace_lwpinfo info; const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info)); @@ -254,6 +255,7 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) { for (const auto &thread : m_threads) static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedByExec(); + SetCurrentThreadID(m_threads.front()->GetID()); SetState(StateType::eStateStopped, true); return; } @@ -312,6 +314,7 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) { } else thread->SetStoppedByBreakpoint(); FixupBreakpointPCAsNeeded(*thread); + SetCurrentThreadID(thread->GetID()); } SetState(StateType::eStateStopped, true); return; @@ -333,11 +336,13 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) { if (wp_index != LLDB_INVALID_INDEX32) { regctx.ClearWatchpointHit(wp_index); thread->SetStoppedByWatchpoint(wp_index); + SetCurrentThreadID(thread->GetID()); SetState(StateType::eStateStopped, true); break; } thread->SetStoppedByTrace(); + SetCurrentThreadID(thread->GetID()); } SetState(StateType::eStateStopped, true); @@ -352,7 +357,7 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) { } void NativeProcessFreeBSD::MonitorSignal(lldb::pid_t pid, int signal) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); struct ptrace_lwpinfo info; const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info)); @@ -370,9 +375,10 @@ void NativeProcessFreeBSD::MonitorSignal(lldb::pid_t pid, int signal) { static_cast<NativeThreadFreeBSD &>(*abs_thread); assert(info.pl_lwpid >= 0); if (info.pl_lwpid == 0 || - static_cast<lldb::tid_t>(info.pl_lwpid) == thread.GetID()) + static_cast<lldb::tid_t>(info.pl_lwpid) == thread.GetID()) { thread.SetStoppedBySignal(info.pl_siginfo.si_signo, &info.pl_siginfo); - else + SetCurrentThreadID(thread.GetID()); + } else thread.SetStoppedWithNoReason(); } SetState(StateType::eStateStopped, true); @@ -380,7 +386,7 @@ void NativeProcessFreeBSD::MonitorSignal(lldb::pid_t pid, int signal) { Status NativeProcessFreeBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, int *result) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + Log *log = GetLog(POSIXLog::Ptrace); Status error; int ret; @@ -424,7 +430,7 @@ NativeProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { } Status NativeProcessFreeBSD::Resume(const ResumeActionList &resume_actions) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); LLDB_LOG(log, "pid {0}", GetID()); Status ret; @@ -521,7 +527,7 @@ Status NativeProcessFreeBSD::Signal(int signo) { Status NativeProcessFreeBSD::Interrupt() { return Halt(); } Status NativeProcessFreeBSD::Kill() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); LLDB_LOG(log, "pid {0}", GetID()); Status error; @@ -608,7 +614,7 @@ Status NativeProcessFreeBSD::GetMemoryRegionInfo(lldb::addr_t load_addr, } Status NativeProcessFreeBSD::PopulateMemoryRegionCache() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); // If our cache is empty, pull the latest. There should always be at least // one memory region if memory region handling is supported. if (!m_mem_region_cache.empty()) { @@ -735,7 +741,7 @@ NativeProcessFreeBSD::GetFileLoadAddress(const llvm::StringRef &file_name, } void NativeProcessFreeBSD::SigchldHandler() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); int status; ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WNOHANG); @@ -780,7 +786,7 @@ bool NativeProcessFreeBSD::HasThreadNoLock(lldb::tid_t thread_id) { } NativeThreadFreeBSD &NativeProcessFreeBSD::AddThread(lldb::tid_t thread_id) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Log *log = GetLog(POSIXLog::Thread); LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); assert(thread_id > 0); @@ -796,7 +802,7 @@ NativeThreadFreeBSD &NativeProcessFreeBSD::AddThread(lldb::tid_t thread_id) { } void NativeProcessFreeBSD::RemoveThread(lldb::tid_t thread_id) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Log *log = GetLog(POSIXLog::Thread); LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id); assert(thread_id > 0); @@ -809,6 +815,9 @@ void NativeProcessFreeBSD::RemoveThread(lldb::tid_t thread_id) { break; } } + + if (GetCurrentThreadID() == thread_id) + SetCurrentThreadID(m_threads.front()->GetID()); } Status NativeProcessFreeBSD::Attach() { @@ -845,7 +854,7 @@ Status NativeProcessFreeBSD::ReadMemory(lldb::addr_t addr, void *buf, unsigned char *dst = static_cast<unsigned char *>(buf); struct ptrace_io_desc io; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); + Log *log = GetLog(POSIXLog::Memory); LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); bytes_read = 0; @@ -873,7 +882,7 @@ Status NativeProcessFreeBSD::WriteMemory(lldb::addr_t addr, const void *buf, Status error; struct ptrace_io_desc io; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); + Log *log = GetLog(POSIXLog::Memory); LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); bytes_written = 0; @@ -953,7 +962,7 @@ bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const { void NativeProcessFreeBSD::MonitorClone(::pid_t child_pid, bool is_vfork, NativeThreadFreeBSD &parent_thread) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); LLDB_LOG(log, "fork, child_pid={0}", child_pid); int status; diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp index 4578138a89b3..143d94069bc6 100644 --- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp @@ -227,7 +227,7 @@ llvm::Error NativeRegisterContextFreeBSD_arm64::CopyHardwareWatchpointsFrom( llvm::Error NativeRegisterContextFreeBSD_arm64::ReadHardwareDebugInfo() { #ifdef LLDB_HAS_FREEBSD_WATCHPOINT - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS)); + Log *log = GetLog(POSIXLog::Registers); // we're fully stateful, so no need to reread control registers ever if (m_read_dbreg) diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp index 80b3527aebce..a75668f3b5c7 100644 --- a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp @@ -75,7 +75,7 @@ Status NativeThreadFreeBSD::Suspend() { void NativeThreadFreeBSD::SetStoppedBySignal(uint32_t signo, const siginfo_t *info) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Log *log = GetLog(POSIXLog::Thread); LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo); SetStopped(); @@ -178,7 +178,7 @@ void NativeThreadFreeBSD::SetStepping() { } std::string NativeThreadFreeBSD::GetName() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Log *log = GetLog(POSIXLog::Thread); std::vector<struct kinfo_proc> kp; int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, @@ -213,7 +213,7 @@ lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; } bool NativeThreadFreeBSD::GetStopReason(ThreadStopInfo &stop_info, std::string &description) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Log *log = GetLog(POSIXLog::Thread); description.clear(); switch (m_state) { @@ -313,3 +313,27 @@ NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) { } return s; } + +llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> +NativeThreadFreeBSD::GetSiginfo() const { + Log *log = GetLog(POSIXLog::Process); + + struct ptrace_lwpinfo info; + const auto siginfo_err = NativeProcessFreeBSD::PtraceWrapper( + PT_LWPINFO, GetID(), &info, sizeof(info)); + if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); + return siginfo_err.ToError(); + } + + if (info.pl_event != PL_EVENT_SIGNAL) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Thread not signaled"); + if (!(info.pl_flags & PL_FLAG_SI)) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No siginfo for thread"); + + return llvm::MemoryBuffer::getMemBufferCopy( + llvm::StringRef(reinterpret_cast<const char *>(&info.pl_siginfo), + sizeof(info.pl_siginfo))); +} diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h index 3ec6daa409e4..6294a7a70963 100644 --- a/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h +++ b/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h @@ -47,6 +47,9 @@ public: Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> + GetSiginfo() const override; + private: // Interface for friend classes diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp index 339d33d25110..e3707365a9c3 100644 --- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp +++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp @@ -137,12 +137,115 @@ bool ProcessFreeBSDKernel::DoUpdateThreadList(ThreadList &old_thread_list, return false; } - const Symbol *pcb_sym = - GetTarget().GetExecutableModule()->FindFirstSymbolWithNameAndType( - ConstString("dumppcb")); - ThreadSP thread_sp(new ThreadFreeBSDKernel( - *this, 1, pcb_sym ? pcb_sym->GetFileAddress() : LLDB_INVALID_ADDRESS)); - new_thread_list.AddThread(thread_sp); + Status error; + + // struct field offsets are written as symbols so that we don't have + // to figure them out ourselves + int32_t offset_p_list = ReadSignedIntegerFromMemory( + FindSymbol("proc_off_p_list"), 4, -1, error); + int32_t offset_p_pid = + ReadSignedIntegerFromMemory(FindSymbol("proc_off_p_pid"), 4, -1, error); + int32_t offset_p_threads = ReadSignedIntegerFromMemory( + FindSymbol("proc_off_p_threads"), 4, -1, error); + int32_t offset_p_comm = ReadSignedIntegerFromMemory( + FindSymbol("proc_off_p_comm"), 4, -1, error); + + int32_t offset_td_tid = ReadSignedIntegerFromMemory( + FindSymbol("thread_off_td_tid"), 4, -1, error); + int32_t offset_td_plist = ReadSignedIntegerFromMemory( + FindSymbol("thread_off_td_plist"), 4, -1, error); + int32_t offset_td_pcb = ReadSignedIntegerFromMemory( + FindSymbol("thread_off_td_pcb"), 4, -1, error); + int32_t offset_td_oncpu = ReadSignedIntegerFromMemory( + FindSymbol("thread_off_td_oncpu"), 4, -1, error); + int32_t offset_td_name = ReadSignedIntegerFromMemory( + FindSymbol("thread_off_td_name"), 4, -1, error); + + // fail if we were not able to read any of the offsets + if (offset_p_list == -1 || offset_p_pid == -1 || offset_p_threads == -1 || + offset_p_comm == -1 || offset_td_tid == -1 || offset_td_plist == -1 || + offset_td_pcb == -1 || offset_td_oncpu == -1 || offset_td_name == -1) + return false; + + // dumptid contains the thread-id of the crashing thread + // dumppcb contains its PCB + int32_t dumptid = + ReadSignedIntegerFromMemory(FindSymbol("dumptid"), 4, -1, error); + lldb::addr_t dumppcb = FindSymbol("dumppcb"); + + // stoppcbs is an array of PCBs on all CPUs + // each element is of size pcb_size + int32_t pcbsize = + ReadSignedIntegerFromMemory(FindSymbol("pcb_size"), 4, -1, error); + lldb::addr_t stoppcbs = FindSymbol("stoppcbs"); + + // from FreeBSD sys/param.h + constexpr size_t fbsd_maxcomlen = 19; + + // iterate through a linked list of all processes + // allproc is a pointer to the first list element, p_list field + // (found at offset_p_list) specifies the next element + for (lldb::addr_t proc = + ReadPointerFromMemory(FindSymbol("allproc"), error); + proc != 0 && proc != LLDB_INVALID_ADDRESS; + proc = ReadPointerFromMemory(proc + offset_p_list, error)) { + int32_t pid = + ReadSignedIntegerFromMemory(proc + offset_p_pid, 4, -1, error); + // process' command-line string + char comm[fbsd_maxcomlen + 1]; + ReadCStringFromMemory(proc + offset_p_comm, comm, sizeof(comm), error); + + // iterate through a linked list of all process' threads + // the initial thread is found in process' p_threads, subsequent + // elements are linked via td_plist field + for (lldb::addr_t td = + ReadPointerFromMemory(proc + offset_p_threads, error); + td != 0; td = ReadPointerFromMemory(td + offset_td_plist, error)) { + int32_t tid = + ReadSignedIntegerFromMemory(td + offset_td_tid, 4, -1, error); + lldb::addr_t pcb_addr = + ReadPointerFromMemory(td + offset_td_pcb, error); + // whether process was on CPU (-1 if not, otherwise CPU number) + int32_t oncpu = + ReadSignedIntegerFromMemory(td + offset_td_oncpu, 4, -2, error); + // thread name + char thread_name[fbsd_maxcomlen + 1]; + ReadCStringFromMemory(td + offset_td_name, thread_name, + sizeof(thread_name), error); + + // if we failed to read TID, ignore this thread + if (tid == -1) + continue; + + std::string thread_desc = llvm::formatv("(pid {0}) {1}", pid, comm); + if (*thread_name && strcmp(thread_name, comm)) { + thread_desc += '/'; + thread_desc += thread_name; + } + + // roughly: + // 1. if the thread crashed, its PCB is going to be at "dumppcb" + // 2. if the thread was on CPU, its PCB is going to be on the CPU + // 3. otherwise, its PCB is in the thread struct + if (tid == dumptid) { + // NB: dumppcb can be LLDB_INVALID_ADDRESS if reading it failed + pcb_addr = dumppcb; + thread_desc += " (crashed)"; + } else if (oncpu != -1) { + // if we managed to read stoppcbs and pcb_size, use them to find + // the correct PCB + if (stoppcbs != LLDB_INVALID_ADDRESS && pcbsize > 0) + pcb_addr = stoppcbs + oncpu * pcbsize; + else + pcb_addr = LLDB_INVALID_ADDRESS; + thread_desc += llvm::formatv(" (on CPU {0})", oncpu); + } + + ThreadSP thread_sp{ + new ThreadFreeBSDKernel(*this, tid, pcb_addr, thread_desc)}; + new_thread_list.AddThread(thread_sp); + } + } } else { const uint32_t num_threads = old_thread_list.GetSize(false); for (uint32_t i = 0; i < num_threads; ++i) @@ -163,6 +266,12 @@ DynamicLoader *ProcessFreeBSDKernel::GetDynamicLoader() { return m_dyld_up.get(); } +lldb::addr_t ProcessFreeBSDKernel::FindSymbol(const char *name) { + ModuleSP mod_sp = GetTarget().GetExecutableModule(); + const Symbol *sym = mod_sp->FindFirstSymbolWithNameAndType(ConstString(name)); + return sym ? sym->GetLoadAddress(&GetTarget()) : LLDB_INVALID_ADDRESS; +} + #if LLDB_ENABLE_FBSDVMCORE ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h index 558eec5403db..5bd463126307 100644 --- a/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h +++ b/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h @@ -46,6 +46,8 @@ public: protected: bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list) override; + + lldb::addr_t FindSymbol(const char* name); }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_FREEBSDKERNEL_PROCESSFREEBSDKERNEL_H diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp index 124c65d587ff..8d304086a163 100644 --- a/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp +++ b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.cpp @@ -24,8 +24,10 @@ using namespace lldb; using namespace lldb_private; ThreadFreeBSDKernel::ThreadFreeBSDKernel(Process &process, lldb::tid_t tid, - lldb::addr_t pcb_addr) - : Thread(process, tid), m_pcb_addr(pcb_addr) {} + lldb::addr_t pcb_addr, + std::string thread_name) + : Thread(process, tid), m_thread_name(std::move(thread_name)), + m_pcb_addr(pcb_addr) {} ThreadFreeBSDKernel::~ThreadFreeBSDKernel() {} @@ -61,9 +63,8 @@ ThreadFreeBSDKernel::CreateRegisterContextForFrame(StackFrame *frame) { m_pcb_addr); break; case llvm::Triple::x86: - m_thread_reg_ctx_sp = - std::make_shared<RegisterContextFreeBSDKernel_i386>( - *this, new RegisterContextFreeBSD_i386(arch), m_pcb_addr); + m_thread_reg_ctx_sp = std::make_shared<RegisterContextFreeBSDKernel_i386>( + *this, new RegisterContextFreeBSD_i386(arch), m_pcb_addr); break; case llvm::Triple::x86_64: m_thread_reg_ctx_sp = diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h index 2842eba64e56..3bc019b63e68 100644 --- a/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h +++ b/lldb/source/Plugins/Process/FreeBSDKernel/ThreadFreeBSDKernel.h @@ -14,7 +14,7 @@ class ThreadFreeBSDKernel : public lldb_private::Thread { public: ThreadFreeBSDKernel(lldb_private::Process &process, lldb::tid_t tid, - lldb::addr_t pcb_addr); + lldb::addr_t pcb_addr, std::string thread_name); ~ThreadFreeBSDKernel() override; @@ -25,10 +25,24 @@ public: lldb::RegisterContextSP CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; + const char *GetName() override { + if (m_thread_name.empty()) + return nullptr; + return m_thread_name.c_str(); + } + + void SetName(const char *name) override { + if (name && name[0]) + m_thread_name.assign(name); + else + m_thread_name.clear(); + } + protected: bool CalculateStopInfo() override; private: + std::string m_thread_name; lldb::RegisterContextSP m_thread_reg_ctx_sp; lldb::addr_t m_pcb_addr; }; diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp index 0420d00e39d6..182eefb7bee7 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -59,7 +59,7 @@ llvm::Expected<std::unique_ptr<NativeProcessProtocol>> NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, MainLoop &mainloop) const { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); Status status; ::pid_t pid = ProcessLauncherPosixFork() @@ -113,7 +113,7 @@ llvm::Expected<std::unique_ptr<NativeProcessProtocol>> NativeProcessNetBSD::Factory::Attach( lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop) const { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); LLDB_LOG(log, "pid = {0:x}", pid); // Retrieve the architecture for the running process. @@ -172,7 +172,7 @@ void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) { } void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid); @@ -207,7 +207,7 @@ void NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) { } void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); ptrace_siginfo_t info; const auto siginfo_err = @@ -359,7 +359,7 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { } void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); ptrace_siginfo_t info; const auto siginfo_err = @@ -383,7 +383,7 @@ void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) { Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, int *result) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + Log *log = GetLog(POSIXLog::Ptrace); Status error; int ret; @@ -459,7 +459,7 @@ static llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo( } Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); LLDB_LOG(log, "pid {0}", GetID()); Status ret; @@ -562,7 +562,7 @@ Status NativeProcessNetBSD::Interrupt() { } Status NativeProcessNetBSD::Kill() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); LLDB_LOG(log, "pid {0}", GetID()); Status error; @@ -654,7 +654,7 @@ Status NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr, } Status NativeProcessNetBSD::PopulateMemoryRegionCache() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); // If our cache is empty, pull the latest. There should always be at least // one memory region if memory region handling is supported. if (!m_mem_region_cache.empty()) { @@ -772,7 +772,7 @@ Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name, } void NativeProcessNetBSD::SigchldHandler() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); int status; ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WALLSIG | WNOHANG); @@ -817,7 +817,7 @@ bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) { } NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Log *log = GetLog(POSIXLog::Thread); LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); assert(thread_id > 0); @@ -833,7 +833,7 @@ NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) { } void NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Log *log = GetLog(POSIXLog::Thread); LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id); assert(thread_id > 0); @@ -882,7 +882,7 @@ Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf, unsigned char *dst = static_cast<unsigned char *>(buf); struct ptrace_io_desc io; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); + Log *log = GetLog(POSIXLog::Memory); LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); bytes_read = 0; @@ -910,7 +910,7 @@ Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf, Status error; struct ptrace_io_desc io; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); + Log *log = GetLog(POSIXLog::Memory); LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); bytes_written = 0; @@ -1013,7 +1013,7 @@ Status NativeProcessNetBSD::ReinitializeThreads() { void NativeProcessNetBSD::MonitorClone(::pid_t child_pid, bool is_vfork, NativeThreadNetBSD &parent_thread) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Log *log = GetLog(POSIXLog::Process); LLDB_LOG(log, "clone, child_pid={0}", child_pid); int status; diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp index 400b89a5fddf..3e8cf9fd9f23 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp @@ -75,7 +75,7 @@ Status NativeThreadNetBSD::Suspend() { void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo, const siginfo_t *info) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Log *log = GetLog(POSIXLog::Thread); LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo); SetStopped(); @@ -178,7 +178,7 @@ void NativeThreadNetBSD::SetStepping() { } std::string NativeThreadNetBSD::GetName() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Log *log = GetLog(POSIXLog::Thread); #ifdef PT_LWPSTATUS struct ptrace_lwpstatus info = {}; @@ -225,7 +225,7 @@ lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, std::string &description) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Log *log = GetLog(POSIXLog::Thread); description.clear(); switch (m_state) { diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp b/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp index f4d0803b264a..7ad88aabc2c0 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp +++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp @@ -13,16 +13,20 @@ using namespace lldb_private; static constexpr Log::Category g_categories[] = { - {{"break"}, {"log breakpoints"}, POSIX_LOG_BREAKPOINTS}, - {{"memory"}, {"log memory reads and writes"}, POSIX_LOG_MEMORY}, - {{"process"}, {"log process events and activities"}, POSIX_LOG_PROCESS}, - {{"ptrace"}, {"log all calls to ptrace"}, POSIX_LOG_PTRACE}, - {{"registers"}, {"log register read/writes"}, POSIX_LOG_REGISTERS}, - {{"thread"}, {"log thread events and activities"}, POSIX_LOG_THREAD}, - {{"watch"}, {"log watchpoint related activities"}, POSIX_LOG_WATCHPOINTS}, + {{"break"}, {"log breakpoints"}, POSIXLog::Breakpoints}, + {{"memory"}, {"log memory reads and writes"}, POSIXLog::Memory}, + {{"process"}, {"log process events and activities"}, POSIXLog::Process}, + {{"ptrace"}, {"log all calls to ptrace"}, POSIXLog::Ptrace}, + {{"registers"}, {"log register read/writes"}, POSIXLog::Registers}, + {{"thread"}, {"log thread events and activities"}, POSIXLog::Thread}, + {{"watch"}, {"log watchpoint related activities"}, POSIXLog::Watchpoints}, }; -Log::Channel ProcessPOSIXLog::g_channel(g_categories, POSIX_LOG_DEFAULT); +static Log::Channel g_channel(g_categories, POSIXLog::Process); + +template <> Log::Channel &lldb_private::LogChannelFor<POSIXLog>() { + return g_channel; +} void ProcessPOSIXLog::Initialize() { static llvm::once_flag g_once_flag; diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h b/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h index c0147c43410f..7b8b6cdbf255 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h +++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h @@ -13,27 +13,25 @@ #include "lldb/Utility/Log.h" -#define POSIX_LOG_PROCESS (1u << 1) -#define POSIX_LOG_THREAD (1u << 2) -#define POSIX_LOG_MEMORY (1u << 4) // Log memory reads/writes calls -#define POSIX_LOG_PTRACE (1u << 5) -#define POSIX_LOG_REGISTERS (1u << 6) -#define POSIX_LOG_BREAKPOINTS (1u << 7) -#define POSIX_LOG_WATCHPOINTS (1u << 8) -#define POSIX_LOG_ALL (UINT32_MAX) -#define POSIX_LOG_DEFAULT POSIX_LOG_PROCESS - namespace lldb_private { -class ProcessPOSIXLog { - static Log::Channel g_channel; +enum class POSIXLog : Log::MaskType { + Breakpoints = Log::ChannelFlag<0>, + Memory = Log::ChannelFlag<1>, + Process = Log::ChannelFlag<2>, + Ptrace = Log::ChannelFlag<3>, + Registers = Log::ChannelFlag<4>, + Thread = Log::ChannelFlag<5>, + Watchpoints = Log::ChannelFlag<6>, + LLVM_MARK_AS_BITMASK_ENUM(Watchpoints) +}; + +class ProcessPOSIXLog { public: static void Initialize(); - - static Log *GetLogIfAllCategoriesSet(uint32_t mask) { - return g_channel.GetLogIfAll(mask); - } }; -} + +template <> Log::Channel &LogChannelFor<POSIXLog>(); +} // namespace lldb_private #endif // liblldb_ProcessPOSIXLog_h_ diff --git a/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp b/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp index d74b66b58afc..b71de4cadb18 100644 --- a/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp +++ b/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "MemoryTagManagerAArch64MTE.h" +#include "llvm/Support/Error.h" +#include <assert.h> using namespace lldb_private; @@ -20,7 +22,7 @@ MemoryTagManagerAArch64MTE::GetLogicalTag(lldb::addr_t addr) const { } lldb::addr_t -MemoryTagManagerAArch64MTE::RemoveNonAddressBits(lldb::addr_t addr) const { +MemoryTagManagerAArch64MTE::RemoveTagBits(lldb::addr_t addr) const { // Here we're ignoring the whole top byte. If you've got MTE // you must also have TBI (top byte ignore). // The other 4 bits could contain other extension bits or @@ -30,7 +32,7 @@ MemoryTagManagerAArch64MTE::RemoveNonAddressBits(lldb::addr_t addr) const { ptrdiff_t MemoryTagManagerAArch64MTE::AddressDiff(lldb::addr_t addr1, lldb::addr_t addr2) const { - return RemoveNonAddressBits(addr1) - RemoveNonAddressBits(addr2); + return RemoveTagBits(addr1) - RemoveTagBits(addr2); } lldb::addr_t MemoryTagManagerAArch64MTE::GetGranuleSize() const { @@ -66,6 +68,15 @@ MemoryTagManagerAArch64MTE::ExpandToGranule(TagRange range) const { return TagRange(new_start, new_len); } +static llvm::Error MakeInvalidRangeErr(lldb::addr_t addr, + lldb::addr_t end_addr) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "End address (0x%" PRIx64 + ") must be greater than the start address (0x%" PRIx64 ")", + end_addr, addr); +} + llvm::Expected<MemoryTagManager::TagRange> MemoryTagManagerAArch64MTE::MakeTaggedRange( lldb::addr_t addr, lldb::addr_t end_addr, @@ -74,17 +85,12 @@ MemoryTagManagerAArch64MTE::MakeTaggedRange( // We must remove tags here otherwise an address with a higher // tag value will always be > the other. ptrdiff_t len = AddressDiff(end_addr, addr); - if (len <= 0) { - return llvm::createStringError( - llvm::inconvertibleErrorCode(), - "End address (0x%" PRIx64 - ") must be greater than the start address (0x%" PRIx64 ")", - end_addr, addr); - } + if (len <= 0) + return MakeInvalidRangeErr(addr, end_addr); // Region addresses will not have memory tags. So when searching // we must use an untagged address. - MemoryRegionInfo::RangeType tag_range(RemoveNonAddressBits(addr), len); + MemoryRegionInfo::RangeType tag_range(RemoveTagBits(addr), len); tag_range = ExpandToGranule(tag_range); // Make a copy so we can use the original for errors and the final return. @@ -123,6 +129,91 @@ MemoryTagManagerAArch64MTE::MakeTaggedRange( return tag_range; } +llvm::Expected<std::vector<MemoryTagManager::TagRange>> +MemoryTagManagerAArch64MTE::MakeTaggedRanges( + lldb::addr_t addr, lldb::addr_t end_addr, + const lldb_private::MemoryRegionInfos &memory_regions) const { + // First check that the range is not inverted. + // We must remove tags here otherwise an address with a higher + // tag value will always be > the other. + ptrdiff_t len = AddressDiff(end_addr, addr); + if (len <= 0) + return MakeInvalidRangeErr(addr, end_addr); + + std::vector<MemoryTagManager::TagRange> tagged_ranges; + // No memory regions means no tagged memory at all + if (memory_regions.empty()) + return tagged_ranges; + + // For the logic to work regions must be in ascending order + // which is what you'd have if you used GetMemoryRegions. + assert(std::is_sorted( + memory_regions.begin(), memory_regions.end(), + [](const MemoryRegionInfo &lhs, const MemoryRegionInfo &rhs) { + return lhs.GetRange().GetRangeBase() < rhs.GetRange().GetRangeBase(); + })); + + // If we're debugging userspace in an OS like Linux that uses an MMU, + // the only reason we'd get overlapping regions is incorrect data. + // It is possible that won't hold for embedded with memory protection + // units (MPUs) that allow overlaps. + // + // For now we're going to assume the former, as there is no good way + // to handle overlaps. For example: + // < requested range > + // [-- region 1 --] + // [-- region 2--] + // Where the first region will reduce the requested range to nothing + // and exit early before it sees the overlap. + MemoryRegionInfos::const_iterator overlap = std::adjacent_find( + memory_regions.begin(), memory_regions.end(), + [](const MemoryRegionInfo &lhs, const MemoryRegionInfo &rhs) { + return rhs.GetRange().DoesIntersect(lhs.GetRange()); + }); + UNUSED_IF_ASSERT_DISABLED(overlap); + assert(overlap == memory_regions.end()); + + // Region addresses will not have memory tags so when searching + // we must use an untagged address. + MemoryRegionInfo::RangeType range(RemoveTagBits(addr), len); + range = ExpandToGranule(range); + + // While there are regions to check and the range has non zero length + for (const MemoryRegionInfo ®ion : memory_regions) { + // If range we're checking has been reduced to zero length, exit early + if (!range.IsValid()) + break; + + // If the region doesn't overlap the range at all, ignore it. + if (!region.GetRange().DoesIntersect(range)) + continue; + + // If it's tagged record this sub-range. + // (assuming that it's already granule aligned) + if (region.GetMemoryTagged()) { + // The region found may extend outside the requested range. + // For example the first region might start before the range. + // We must only add what covers the requested range. + lldb::addr_t start = + std::max(range.GetRangeBase(), region.GetRange().GetRangeBase()); + lldb::addr_t end = + std::min(range.GetRangeEnd(), region.GetRange().GetRangeEnd()); + tagged_ranges.push_back(MemoryTagManager::TagRange(start, end - start)); + } + + // Move the range up to start at the end of the region. + lldb::addr_t old_end = range.GetRangeEnd(); + // This "slides" the range so it moves the end as well. + range.SetRangeBase(region.GetRange().GetRangeEnd()); + // So we set the end back to the original end address after sliding it up. + range.SetRangeEnd(old_end); + // (if the above were to try to set end < begin the range will just be set + // to 0 size) + } + + return tagged_ranges; +} + llvm::Expected<std::vector<lldb::addr_t>> MemoryTagManagerAArch64MTE::UnpackTagsData(const std::vector<uint8_t> &tags, size_t granules /*=0*/) const { diff --git a/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h b/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h index d4e8249da93f..7cda728b140f 100644 --- a/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h +++ b/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h @@ -27,7 +27,7 @@ public: size_t GetTagSizeInBytes() const override; lldb::addr_t GetLogicalTag(lldb::addr_t addr) const override; - lldb::addr_t RemoveNonAddressBits(lldb::addr_t addr) const override; + lldb::addr_t RemoveTagBits(lldb::addr_t addr) const override; ptrdiff_t AddressDiff(lldb::addr_t addr1, lldb::addr_t addr2) const override; TagRange ExpandToGranule(TagRange range) const override; @@ -36,6 +36,10 @@ public: lldb::addr_t addr, lldb::addr_t end_addr, const lldb_private::MemoryRegionInfos &memory_regions) const override; + llvm::Expected<std::vector<TagRange>> MakeTaggedRanges( + lldb::addr_t addr, lldb::addr_t end_addr, + const lldb_private::MemoryRegionInfos &memory_regions) const override; + llvm::Expected<std::vector<lldb::addr_t>> UnpackTagsData(const std::vector<uint8_t> &tags, size_t granules = 0) const override; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp index 6c130be7b741..d6c4a8687ec5 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp @@ -178,10 +178,10 @@ static const lldb_private::RegisterSet g_reg_sets_arm64[k_num_register_sets] = { g_sve_regnums_arm64}}; static const lldb_private::RegisterSet g_reg_set_pauth_arm64 = { - "Pointer Authentication Registers", "pauth", k_num_pauth_register, NULL}; + "Pointer Authentication Registers", "pauth", k_num_pauth_register, nullptr}; static const lldb_private::RegisterSet g_reg_set_mte_arm64 = { - "MTE Control Register", "mte", k_num_mte_register, NULL}; + "MTE Control Register", "mte", k_num_mte_register, nullptr}; RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64( const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index b5b105351de5..f6526d03863b 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -173,6 +173,13 @@ bool GDBRemoteCommunicationClient::GetQXferMemoryMapReadSupported() { return m_supports_qXfer_memory_map_read == eLazyBoolYes; } +bool GDBRemoteCommunicationClient::GetQXferSigInfoReadSupported() { + if (m_supports_qXfer_siginfo_read == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_qXfer_siginfo_read == eLazyBoolYes; +} + uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() { if (m_max_packet_size == 0) { GetRemoteQSupported(); @@ -273,6 +280,7 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) { m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; m_supports_qXfer_features_read = eLazyBoolCalculate; m_supports_qXfer_memory_map_read = eLazyBoolCalculate; + m_supports_qXfer_siginfo_read = eLazyBoolCalculate; m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; m_uses_native_signals = eLazyBoolCalculate; m_supports_qProcessInfoPID = true; @@ -320,6 +328,7 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() { m_supports_augmented_libraries_svr4_read = eLazyBoolNo; m_supports_qXfer_features_read = eLazyBoolNo; m_supports_qXfer_memory_map_read = eLazyBoolNo; + m_supports_qXfer_siginfo_read = eLazyBoolNo; m_supports_multiprocess = eLazyBoolNo; m_supports_qEcho = eLazyBoolNo; m_supports_QPassSignals = eLazyBoolNo; @@ -362,6 +371,8 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() { m_supports_qXfer_features_read = eLazyBoolYes; else if (x == "qXfer:memory-map:read+") m_supports_qXfer_memory_map_read = eLazyBoolYes; + else if (x == "qXfer:siginfo:read+") + m_supports_qXfer_siginfo_read = eLazyBoolYes; else if (x == "qEcho") m_supports_qEcho = eLazyBoolYes; else if (x == "QPassSignals+") diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index c69c33bb1c15..58ed22187747 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -337,6 +337,8 @@ public: bool GetQXferMemoryMapReadSupported(); + bool GetQXferSigInfoReadSupported(); + LazyBool SupportsAllocDeallocMemory() // const { // Uncomment this to have lldb pretend the debug server doesn't respond to @@ -551,6 +553,7 @@ protected: LazyBool m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; LazyBool m_supports_qXfer_features_read = eLazyBoolCalculate; LazyBool m_supports_qXfer_memory_map_read = eLazyBoolCalculate; + LazyBool m_supports_qXfer_siginfo_read = eLazyBoolCalculate; LazyBool m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; LazyBool m_supports_jThreadExtendedInfo = eLazyBoolCalculate; LazyBool m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolCalculate; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp deleted file mode 100644 index c91d7cb5ac30..000000000000 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp +++ /dev/null @@ -1,314 +0,0 @@ -//===-- GDBRemoteCommunicationReplayServer.cpp ----------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include <cerrno> - -#include "lldb/Host/Config.h" -#include "llvm/ADT/ScopeExit.h" - -#include "GDBRemoteCommunicationReplayServer.h" -#include "ProcessGDBRemoteLog.h" - -// C Includes -// C++ Includes -#include <cstring> - -// Project includes -#include "lldb/Host/ThreadLauncher.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/Utility/Event.h" -#include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/StreamString.h" -#include "lldb/Utility/StringExtractorGDBRemote.h" - -using namespace llvm; -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_gdb_remote; - -/// Check if the given expected packet matches the actual packet. -static bool unexpected(llvm::StringRef expected, llvm::StringRef actual) { - // The 'expected' string contains the raw data, including the leading $ and - // trailing checksum. The 'actual' string contains only the packet's content. - if (expected.contains(actual)) - return false; - // Contains a PID which might be different. - if (expected.contains("vAttach")) - return false; - // Contains a ascii-hex-path. - if (expected.contains("QSetSTD")) - return false; - // Contains environment values. - if (expected.contains("QEnvironment")) - return false; - - return true; -} - -/// Check if we should reply to the given packet. -static bool skip(llvm::StringRef data) { - assert(!data.empty() && "Empty packet?"); - - // We've already acknowledge the '+' packet so we're done here. - if (data == "+") - return true; - - /// Don't 't reply to ^C. We need this because of stop reply packets, which - /// are only returned when the target halts. Reproducers synchronize these - /// 'asynchronous' replies, by recording them as a regular replies to the - /// previous packet (e.g. vCont). As a result, we should ignore real - /// asynchronous requests. - if (data.data()[0] == 0x03) - return true; - - return false; -} - -GDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer() - : GDBRemoteCommunication("gdb-replay", "gdb-replay.rx_packet"), - m_async_broadcaster(nullptr, "lldb.gdb-replay.async-broadcaster"), - m_async_listener_sp( - Listener::MakeListener("lldb.gdb-replay.async-listener")), - m_async_thread_state_mutex() { - m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, - "async thread continue"); - m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, - "async thread should exit"); - - const uint32_t async_event_mask = - eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; - m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster, - async_event_mask); -} - -GDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() { - StopAsyncThread(); -} - -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( - Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) { - std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); - - StringExtractorGDBRemote packet; - PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false); - - if (packet_result != PacketResult::Success) { - if (!IsConnected()) { - error.SetErrorString("lost connection"); - quit = true; - } else { - error.SetErrorString("timeout"); - } - return packet_result; - } - - m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); - - // Check if we should reply to this packet. - if (skip(packet.GetStringRef())) - return PacketResult::Success; - - // This completes the handshake. Since m_send_acks was true, we can unset it - // already. - if (packet.GetStringRef() == "QStartNoAckMode") - m_send_acks = false; - - // A QEnvironment packet is sent for every environment variable. If the - // number of environment variables is different during replay, the replies - // become out of sync. - if (packet.GetStringRef().find("QEnvironment") == 0) - return SendRawPacketNoLock("$OK#9a"); - - Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - while (!m_packet_history.empty()) { - // Pop last packet from the history. - GDBRemotePacket entry = m_packet_history.back(); - m_packet_history.pop_back(); - - // Decode run-length encoding. - const std::string expanded_data = - GDBRemoteCommunication::ExpandRLE(entry.packet.data); - - // We've handled the handshake implicitly before. Skip the packet and move - // on. - if (entry.packet.data == "+") - continue; - - if (entry.type == GDBRemotePacket::ePacketTypeSend) { - if (unexpected(expanded_data, packet.GetStringRef())) { - LLDB_LOG(log, - "GDBRemoteCommunicationReplayServer expected packet: '{0}'", - expanded_data); - LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'", - packet.GetStringRef()); -#ifndef NDEBUG - // This behaves like a regular assert, but prints the expected and - // received packet before aborting. - printf("Reproducer expected packet: '%s'\n", expanded_data.c_str()); - printf("Reproducer received packet: '%s'\n", - packet.GetStringRef().data()); - llvm::report_fatal_error("Encountered unexpected packet during replay"); -#endif - return PacketResult::ErrorSendFailed; - } - - // Ignore QEnvironment packets as they're handled earlier. - if (expanded_data.find("QEnvironment") == 1) { - assert(m_packet_history.back().type == - GDBRemotePacket::ePacketTypeRecv); - m_packet_history.pop_back(); - } - - continue; - } - - if (entry.type == GDBRemotePacket::ePacketTypeInvalid) { - LLDB_LOG( - log, - "GDBRemoteCommunicationReplayServer skipped invalid packet: '{0}'", - packet.GetStringRef()); - continue; - } - - LLDB_LOG(log, - "GDBRemoteCommunicationReplayServer replied to '{0}' with '{1}'", - packet.GetStringRef(), entry.packet.data); - return SendRawPacketNoLock(entry.packet.data); - } - - quit = true; - - return packet_result; -} - -llvm::Error -GDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) { - auto error_or_file = MemoryBuffer::getFile(path.GetPath()); - if (auto err = error_or_file.getError()) - return errorCodeToError(err); - - yaml::Input yin((*error_or_file)->getBuffer()); - yin >> m_packet_history; - - if (auto err = yin.error()) - return errorCodeToError(err); - - // We want to manipulate the vector like a stack so we need to reverse the - // order of the packets to have the oldest on at the back. - std::reverse(m_packet_history.begin(), m_packet_history.end()); - - return Error::success(); -} - -bool GDBRemoteCommunicationReplayServer::StartAsyncThread() { - std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); - if (!m_async_thread.IsJoinable()) { - // Create a thread that watches our internal state and controls which - // events make it to clients (into the DCProcess event queue). - llvm::Expected<HostThread> async_thread = ThreadLauncher::LaunchThread( - "<lldb.gdb-replay.async>", - GDBRemoteCommunicationReplayServer::AsyncThread, this); - if (!async_thread) { - LLDB_LOG_ERROR(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), - async_thread.takeError(), - "failed to launch host thread: {}"); - return false; - } - m_async_thread = *async_thread; - } - - // Wait for handshake. - m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); - - return m_async_thread.IsJoinable(); -} - -void GDBRemoteCommunicationReplayServer::StopAsyncThread() { - std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); - - if (!m_async_thread.IsJoinable()) - return; - - // Request thread to stop. - m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit); - - // Disconnect client. - Disconnect(); - - // Stop the thread. - m_async_thread.Join(nullptr); - m_async_thread.Reset(); -} - -void GDBRemoteCommunicationReplayServer::ReceivePacket( - GDBRemoteCommunicationReplayServer &server, bool &done) { - Status error; - bool interrupt; - auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1), - error, interrupt, done); - if (packet_result != GDBRemoteCommunication::PacketResult::Success && - packet_result != - GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) { - done = true; - } else { - server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); - } -} - -thread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) { - GDBRemoteCommunicationReplayServer *server = - (GDBRemoteCommunicationReplayServer *)arg; - auto D = make_scope_exit([&]() { server->Disconnect(); }); - EventSP event_sp; - bool done = false; - while (!done) { - if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) { - const uint32_t event_type = event_sp->GetType(); - if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) { - switch (event_type) { - case eBroadcastBitAsyncContinue: - ReceivePacket(*server, done); - if (done) - return {}; - break; - case eBroadcastBitAsyncThreadShouldExit: - default: - return {}; - } - } - } - } - - return {}; -} - -Status GDBRemoteCommunicationReplayServer::Connect( - process_gdb_remote::GDBRemoteCommunicationClient &client) { - repro::Loader *loader = repro::Reproducer::Instance().GetLoader(); - if (!loader) - return Status("No loader provided."); - - static std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>> - multi_loader = repro::MultiLoader<repro::GDBRemoteProvider>::Create( - repro::Reproducer::Instance().GetLoader()); - if (!multi_loader) - return Status("No gdb remote provider found."); - - llvm::Optional<std::string> history_file = multi_loader->GetNextFile(); - if (!history_file) - return Status("No gdb remote packet log found."); - - if (auto error = LoadReplayHistory(FileSpec(*history_file))) - return Status("Unable to load replay history"); - - if (auto error = GDBRemoteCommunication::ConnectLocally(client, *this)) - return Status("Unable to connect to replay server"); - - return {}; -} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h deleted file mode 100644 index 2f8770d0accf..000000000000 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h +++ /dev/null @@ -1,88 +0,0 @@ -//===-- GDBRemoteCommunicationReplayServer.h --------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONREPLAYSERVER_H -#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONREPLAYSERVER_H - -// Other libraries and framework includes -#include "GDBRemoteCommunication.h" -#include "GDBRemoteCommunicationClient.h" -#include "GDBRemoteCommunicationHistory.h" - -// Project includes -#include "lldb/Host/HostThread.h" -#include "lldb/Utility/Broadcaster.h" -#include "lldb/lldb-private-forward.h" -#include "llvm/Support/Error.h" - -// C Includes -// C++ Includes -#include <functional> -#include <map> -#include <thread> - -class StringExtractorGDBRemote; - -namespace lldb_private { -namespace process_gdb_remote { - -class ProcessGDBRemote; - -/// Dummy GDB server that replays packets from the GDB Remote Communication -/// history. This is used to replay GDB packets. -class GDBRemoteCommunicationReplayServer : public GDBRemoteCommunication { -public: - GDBRemoteCommunicationReplayServer(); - - ~GDBRemoteCommunicationReplayServer() override; - - PacketResult GetPacketAndSendResponse(Timeout<std::micro> timeout, - Status &error, bool &interrupt, - bool &quit); - - bool HandshakeWithClient() { return GetAck() == PacketResult::Success; } - - llvm::Error LoadReplayHistory(const FileSpec &path); - - bool StartAsyncThread(); - void StopAsyncThread(); - - Status Connect(process_gdb_remote::GDBRemoteCommunicationClient &client); - -protected: - enum { - eBroadcastBitAsyncContinue = (1 << 0), - eBroadcastBitAsyncThreadShouldExit = (1 << 1), - }; - - static void ReceivePacket(GDBRemoteCommunicationReplayServer &server, - bool &done); - static lldb::thread_result_t AsyncThread(void *arg); - - /// Replay history with the oldest packet at the end. - std::vector<GDBRemotePacket> m_packet_history; - - /// Server thread. - Broadcaster m_async_broadcaster; - lldb::ListenerSP m_async_listener_sp; - HostThread m_async_thread; - std::recursive_mutex m_async_thread_state_mutex; - - bool m_skip_acks = false; - -private: - GDBRemoteCommunicationReplayServer( - const GDBRemoteCommunicationReplayServer &) = delete; - const GDBRemoteCommunicationReplayServer & - operator=(const GDBRemoteCommunicationReplayServer &) = delete; -}; - -} // namespace process_gdb_remote -} // namespace lldb_private - -#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONREPLAYSERVER_H diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 30f14a52dfb5..123a8198a89b 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1086,7 +1086,7 @@ void GDBRemoteCommunicationServerLLGS::NewSubprocess( } void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() { - Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_COMM)); + Log *log = GetLog(GDBRLog::Comm); bool interrupt = false; bool done = false; @@ -2920,6 +2920,18 @@ GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object, return std::move(*buffer_or_error); } + if (object == "siginfo") { + NativeThreadProtocol *thread = m_current_process->GetCurrentThread(); + if (!thread) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "no current thread"); + + auto buffer_or_error = thread->GetSiginfo(); + if (!buffer_or_error) + return buffer_or_error.takeError(); + return std::move(*buffer_or_error); + } + if (object == "libraries-svr4") { auto library_list = m_current_process->GetLoadedSVR4Libraries(); if (!library_list) @@ -3838,6 +3850,8 @@ std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures( ret.push_back("qXfer:auxv:read+"); if (bool(plugin_features & Extension::libraries_svr4)) ret.push_back("qXfer:libraries-svr4:read+"); + if (bool(plugin_features & Extension::siginfo_read)) + ret.push_back("qXfer:siginfo:read+"); if (bool(plugin_features & Extension::memory_tagging)) ret.push_back("memory-tagging+"); if (bool(plugin_features & Extension::savecore)) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.cpp new file mode 100644 index 000000000000..b391edced695 --- /dev/null +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.cpp @@ -0,0 +1,86 @@ +//===-- GDBRemoteRegisterFallback.cpp -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "GDBRemoteRegisterFallback.h" + +namespace lldb_private { +namespace process_gdb_remote { + +#define REG(name, size) \ + DynamicRegisterInfo::Register { \ + ConstString(#name), empty_alt_name, reg_set, size, LLDB_INVALID_INDEX32, \ + lldb::eEncodingUint, lldb::eFormatHex, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, {}, {} \ + } +#define R64(name) REG(name, 8) +#define R32(name) REG(name, 4) + +static std::vector<DynamicRegisterInfo::Register> GetRegisters_aarch64() { + ConstString empty_alt_name; + ConstString reg_set{"general purpose registers"}; + + std::vector<DynamicRegisterInfo::Register> registers{ + R64(x0), R64(x1), R64(x2), R64(x3), R64(x4), R64(x5), R64(x6), + R64(x7), R64(x8), R64(x9), R64(x10), R64(x11), R64(x12), R64(x13), + R64(x14), R64(x15), R64(x16), R64(x17), R64(x18), R64(x19), R64(x20), + R64(x21), R64(x22), R64(x23), R64(x24), R64(x25), R64(x26), R64(x27), + R64(x28), R64(x29), R64(x30), R64(sp), R64(pc), R32(cpsr), + }; + + return registers; +} + +static std::vector<DynamicRegisterInfo::Register> GetRegisters_x86() { + ConstString empty_alt_name; + ConstString reg_set{"general purpose registers"}; + + std::vector<DynamicRegisterInfo::Register> registers{ + R32(eax), R32(ecx), R32(edx), R32(ebx), R32(esp), R32(ebp), + R32(esi), R32(edi), R32(eip), R32(eflags), R32(cs), R32(ss), + R32(ds), R32(es), R32(fs), R32(gs), + }; + + return registers; +} + +static std::vector<DynamicRegisterInfo::Register> GetRegisters_x86_64() { + ConstString empty_alt_name; + ConstString reg_set{"general purpose registers"}; + + std::vector<DynamicRegisterInfo::Register> registers{ + R64(rax), R64(rbx), R64(rcx), R64(rdx), R64(rsi), R64(rdi), + R64(rbp), R64(rsp), R64(r8), R64(r9), R64(r10), R64(r11), + R64(r12), R64(r13), R64(r14), R64(r15), R64(rip), R32(eflags), + R32(cs), R32(ss), R32(ds), R32(es), R32(fs), R32(gs), + }; + + return registers; +} + +#undef R32 +#undef R64 +#undef REG + +std::vector<DynamicRegisterInfo::Register> +GetFallbackRegisters(const ArchSpec &arch_to_use) { + switch (arch_to_use.GetMachine()) { + case llvm::Triple::aarch64: + return GetRegisters_aarch64(); + case llvm::Triple::x86: + return GetRegisters_x86(); + case llvm::Triple::x86_64: + return GetRegisters_x86_64(); + default: + break; + } + + return {}; +} + +} // namespace process_gdb_remote +} // namespace lldb_private diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.h new file mode 100644 index 000000000000..82e03c6b9b1c --- /dev/null +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterFallback.h @@ -0,0 +1,26 @@ +//===-- GDBRemoteRegisterFallback.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERFALLBACK_H +#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERFALLBACK_H + +#include <vector> + +#include "lldb/Target/DynamicRegisterInfo.h" +#include "lldb/Utility/ArchSpec.h" + +namespace lldb_private { +namespace process_gdb_remote { + +std::vector<DynamicRegisterInfo::Register> +GetFallbackRegisters(const ArchSpec &arch_to_use); + +} // namespace process_gdb_remote +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTEREGISTERFALLBACK_H diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 93fe36c0d9d6..d8ad0b4e4e4b 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -23,13 +23,6 @@ #include <ctime> #include <sys/types.h> -#include <algorithm> -#include <csignal> -#include <map> -#include <memory> -#include <mutex> -#include <sstream> - #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -70,8 +63,16 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" +#include <algorithm> +#include <csignal> +#include <map> +#include <memory> +#include <mutex> +#include <sstream> +#include <thread> #include "GDBRemoteRegisterContext.h" +#include "GDBRemoteRegisterFallback.h" #include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" @@ -253,9 +254,8 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, m_addr_to_mmap_size(), m_thread_create_bp_sp(), m_waiting_for_attach(false), m_destroy_tried_resuming(false), m_command_sp(), m_breakpoint_pc_offset(0), - m_initial_tid(LLDB_INVALID_THREAD_ID), m_replay_mode(false), - m_allow_flash_writes(false), m_erased_flash_ranges(), - m_vfork_in_progress(false) { + m_initial_tid(LLDB_INVALID_THREAD_ID), m_allow_flash_writes(false), + m_erased_flash_ranges(), m_vfork_in_progress(false) { m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, @@ -395,6 +395,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { // 2 - If the target definition doesn't have any of the info from the // target.xml (registers) then proceed to read the target.xml. // 3 - Fall back on the qRegisterInfo packets. + // 4 - Use hardcoded defaults if available. FileSpec target_definition_fspec = GetGlobalPluginProperties().GetTargetDefinitionFile(); @@ -508,6 +509,9 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { } } + if (registers.empty()) + registers = GetFallbackRegisters(arch_to_use); + AddRemoteRegisters(registers, arch_to_use); } @@ -525,7 +529,7 @@ Status ProcessGDBRemote::WillAttachToProcessWithName(const char *process_name, } Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) { - Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + Log *log = GetLog(GDBRLog::Process); Status error(WillLaunchOrAttach()); if (error.Fail()) @@ -602,8 +606,7 @@ Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) { ReadModuleFromMemory(FileSpec(namebuf), standalone_value); } - Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet( - LIBLLDB_LOG_DYNAMIC_LOADER)); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); if (module_sp.get()) { target.GetImages().AppendIfNeeded(module_sp, false); @@ -3316,24 +3319,6 @@ Status ProcessGDBRemote::DoSignal(int signo) { return error; } -Status ProcessGDBRemote::ConnectToReplayServer() { - Status status = m_gdb_replay_server.Connect(m_gdb_comm); - if (status.Fail()) - return status; - - // Enable replay mode. - m_replay_mode = true; - - // Start server thread. - m_gdb_replay_server.StartAsyncThread(); - - // Start client thread. - StartAsyncThread(); - - // Do the usual setup. - return ConnectToDebugserver(""); -} - Status ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) { // Make sure we aren't already connected? @@ -4370,9 +4355,9 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess( } else if (name == "osabi") { node.GetElementText(target_info.osabi); } else if (name == "xi:include" || name == "include") { - llvm::StringRef href = node.GetAttributeValue("href"); + std::string href = node.GetAttributeValue("href"); if (!href.empty()) - target_info.includes.push_back(href.str()); + target_info.includes.push_back(href); } else if (name == "feature") { feature_nodes.push_back(node); } else if (name == "groups") { @@ -4411,9 +4396,9 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess( const XMLNode &node) -> bool { llvm::StringRef name = node.GetName(); if (name == "xi:include" || name == "include") { - llvm::StringRef href = node.GetAttributeValue("href"); + std::string href = node.GetAttributeValue("href"); if (!href.empty()) - target_info.includes.push_back(href.str()); + target_info.includes.push_back(href); } return true; }); @@ -4549,7 +4534,7 @@ llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() { "Error finding library-list-svr4 xml element"); // main link map structure - llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm"); + std::string main_lm = root_element.GetAttributeValue("main-lm"); // FIXME: we're silently ignoring invalid data here if (!main_lm.empty()) llvm::to_integer(main_lm, list.m_link_map); @@ -4637,15 +4622,15 @@ llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() { "library", [log, &list](const XMLNode &library) -> bool { LoadedModuleInfoList::LoadedModuleInfo module; - llvm::StringRef name = library.GetAttributeValue("name"); - module.set_name(name.str()); + std::string name = library.GetAttributeValue("name"); + module.set_name(name); // The base address of a given library will be the address of its // first section. Most remotes send only one section for Windows // targets for example. const XMLNode §ion = library.FindFirstChildElementWithName("section"); - llvm::StringRef address = section.GetAttributeValue("address"); + std::string address = section.GetAttributeValue("address"); uint64_t address_value = LLDB_INVALID_ADDRESS; llvm::to_integer(address, address_value); module.set_base(address_value); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 488336b8c1b8..bdf130e3ec11 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -34,7 +34,6 @@ #include "lldb/lldb-private-forward.h" #include "GDBRemoteCommunicationClient.h" -#include "GDBRemoteCommunicationReplayServer.h" #include "GDBRemoteRegisterContext.h" #include "llvm/ADT/DenseMap.h" @@ -251,7 +250,6 @@ protected: }; GDBRemoteCommunicationClient m_gdb_comm; - GDBRemoteCommunicationReplayServer m_gdb_replay_server; std::atomic<lldb::pid_t> m_debugserver_pid; llvm::Optional<StringExtractorGDBRemote> m_last_stop_packet; @@ -292,7 +290,6 @@ protected: lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach bool m_use_g_packet_for_reading; - bool m_replay_mode; bool m_allow_flash_writes; using FlashRangeVector = lldb_private::RangeVector<lldb::addr_t, size_t>; using FlashRange = FlashRangeVector::Entry; @@ -320,8 +317,6 @@ protected: bool DoUpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) override; - Status ConnectToReplayServer(); - Status EstablishConnectionIfNeeded(const ProcessInfo &process_info); Status LaunchAndConnectToDebugserver(const ProcessInfo &process_info); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp index 40990ef66494..3322f6b8048a 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp @@ -15,25 +15,29 @@ using namespace lldb_private; using namespace lldb_private::process_gdb_remote; static constexpr Log::Category g_categories[] = { - {{"async"}, {"log asynchronous activity"}, GDBR_LOG_ASYNC}, - {{"break"}, {"log breakpoints"}, GDBR_LOG_BREAKPOINTS}, - {{"comm"}, {"log communication activity"}, GDBR_LOG_COMM}, - {{"packets"}, {"log gdb remote packets"}, GDBR_LOG_PACKETS}, - {{"memory"}, {"log memory reads and writes"}, GDBR_LOG_MEMORY}, + {{"async"}, {"log asynchronous activity"}, GDBRLog::Async}, + {{"break"}, {"log breakpoints"}, GDBRLog::Breakpoints}, + {{"comm"}, {"log communication activity"}, GDBRLog::Comm}, + {{"packets"}, {"log gdb remote packets"}, GDBRLog::Packets}, + {{"memory"}, {"log memory reads and writes"}, GDBRLog::Memory}, {{"data-short"}, {"log memory bytes for memory reads and writes for short transactions " "only"}, - GDBR_LOG_MEMORY_DATA_SHORT}, + GDBRLog::MemoryDataShort}, {{"data-long"}, {"log memory bytes for memory reads and writes for all transactions"}, - GDBR_LOG_MEMORY_DATA_LONG}, - {{"process"}, {"log process events and activities"}, GDBR_LOG_PROCESS}, - {{"step"}, {"log step related activities"}, GDBR_LOG_STEP}, - {{"thread"}, {"log thread events and activities"}, GDBR_LOG_THREAD}, - {{"watch"}, {"log watchpoint related activities"}, GDBR_LOG_WATCHPOINTS}, + GDBRLog::MemoryDataLong}, + {{"process"}, {"log process events and activities"}, GDBRLog::Process}, + {{"step"}, {"log step related activities"}, GDBRLog::Step}, + {{"thread"}, {"log thread events and activities"}, GDBRLog::Thread}, + {{"watch"}, {"log watchpoint related activities"}, GDBRLog::Watchpoints}, }; -Log::Channel ProcessGDBRemoteLog::g_channel(g_categories, GDBR_LOG_DEFAULT); +static Log::Channel g_channel(g_categories, GDBRLog::Packets); + +template <> Log::Channel &lldb_private::LogChannelFor<GDBRLog>() { + return g_channel; +} void ProcessGDBRemoteLog::Initialize() { static llvm::once_flag g_once_flag; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h index bd3e993cf72a..44e390ec8cad 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h @@ -11,35 +11,52 @@ #include "lldb/Utility/Log.h" -#define GDBR_LOG_PROCESS (1u << 1) -#define GDBR_LOG_THREAD (1u << 2) -#define GDBR_LOG_PACKETS (1u << 3) -#define GDBR_LOG_MEMORY (1u << 4) // Log memory reads/writes calls -#define GDBR_LOG_MEMORY_DATA_SHORT \ - (1u << 5) // Log short memory reads/writes bytes -#define GDBR_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes -#define GDBR_LOG_BREAKPOINTS (1u << 7) -#define GDBR_LOG_WATCHPOINTS (1u << 8) -#define GDBR_LOG_STEP (1u << 9) -#define GDBR_LOG_COMM (1u << 10) -#define GDBR_LOG_ASYNC (1u << 11) -#define GDBR_LOG_ALL (UINT32_MAX) -#define GDBR_LOG_DEFAULT GDBR_LOG_PACKETS - namespace lldb_private { namespace process_gdb_remote { -class ProcessGDBRemoteLog { - static Log::Channel g_channel; +enum class GDBRLog : Log::MaskType { + Async = Log::ChannelFlag<0>, + Breakpoints = Log::ChannelFlag<1>, + Comm = Log::ChannelFlag<2>, + Memory = Log::ChannelFlag<3>, // Log memory reads/writes calls + MemoryDataLong = Log::ChannelFlag<4>, // Log all memory reads/writes bytes + MemoryDataShort = Log::ChannelFlag<5>, // Log short memory reads/writes bytes + Packets = Log::ChannelFlag<6>, + Process = Log::ChannelFlag<7>, + Step = Log::ChannelFlag<8>, + Thread = Log::ChannelFlag<9>, + Watchpoints = Log::ChannelFlag<10>, + LLVM_MARK_AS_BITMASK_ENUM(Watchpoints) +}; +#define GDBR_LOG_PROCESS ::lldb_private::process_gdb_remote::GDBRLog::Process +#define GDBR_LOG_THREAD ::lldb_private::process_gdb_remote::GDBRLog::Thread +#define GDBR_LOG_PACKETS ::lldb_private::process_gdb_remote::GDBRLog::Packets +#define GDBR_LOG_MEMORY ::lldb_private::process_gdb_remote::GDBRLog::Memory +#define GDBR_LOG_MEMORY_DATA_SHORT \ + ::lldb_private::process_gdb_remote::GDBRLog::MemoryDataShort +#define GDBR_LOG_MEMORY_DATA_LONG \ + ::lldb_private::process_gdb_remote::GDBRLog::MemoryDataLong +#define GDBR_LOG_BREAKPOINTS \ + ::lldb_private::process_gdb_remote::GDBRLog::Breakpoints +#define GDBR_LOG_WATCHPOINTS \ + ::lldb_private::process_gdb_remote::GDBRLog::Watchpoints +#define GDBR_LOG_STEP ::lldb_private::process_gdb_remote::GDBRLog::Step +#define GDBR_LOG_COMM ::lldb_private::process_gdb_remote::GDBRLog::Comm +#define GDBR_LOG_ASYNC ::lldb_private::process_gdb_remote::GDBRLog::Async + +class ProcessGDBRemoteLog { public: static void Initialize(); - static Log *GetLogIfAllCategoriesSet(uint32_t mask) { return g_channel.GetLogIfAll(mask); } - static Log *GetLogIfAnyCategoryIsSet(uint32_t mask) { return g_channel.GetLogIfAny(mask); } + static Log *GetLogIfAllCategoriesSet(GDBRLog mask) { return GetLog(mask); } + static Log *GetLogIfAnyCategoryIsSet(GDBRLog mask) { return GetLog(mask); } }; } // namespace process_gdb_remote + +template <> Log::Channel &LogChannelFor<process_gdb_remote::GDBRLog>(); + } // namespace lldb_private #endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_PROCESSGDBREMOTELOG_H diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 2a9896e41085..3d23c074c1be 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -39,7 +39,7 @@ ThreadGDBRemote::ThreadGDBRemote(Process &process, lldb::tid_t tid) m_dispatch_queue_t(LLDB_INVALID_ADDRESS), m_queue_kind(eQueueKindUnknown), m_queue_serial_number(LLDB_INVALID_QUEUE_ID), m_associated_with_libdispatch_queue(eLazyBoolCalculate) { - Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD)); + Log *log = GetLog(GDBRLog::Thread); LLDB_LOG(log, "this = {0}, pid = {1}, tid = {2}", this, process.GetID(), GetID()); // At this point we can clone reg_info for architectures supporting @@ -54,7 +54,7 @@ ThreadGDBRemote::ThreadGDBRemote(Process &process, lldb::tid_t tid) ThreadGDBRemote::~ThreadGDBRemote() { ProcessSP process_sp(GetProcess()); - Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD)); + Log *log = GetLog(GDBRLog::Thread); LLDB_LOG(log, "this = {0}, pid = {1}, tid = {2}", this, process_sp ? process_sp->GetID() : LLDB_INVALID_PROCESS_ID, GetID()); DestroyThread(); @@ -222,7 +222,7 @@ void ThreadGDBRemote::SetAssociatedWithLibdispatchQueue( StructuredData::ObjectSP ThreadGDBRemote::FetchThreadExtendedInfo() { StructuredData::ObjectSP object_sp; const lldb::user_id_t tid = GetProtocolID(); - Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD)); + Log *log = GetLog(GDBRLog::Thread); LLDB_LOGF(log, "Fetching extended information for thread %4.4" PRIx64, tid); ProcessSP process_sp(GetProcess()); if (process_sp) { @@ -236,7 +236,7 @@ StructuredData::ObjectSP ThreadGDBRemote::FetchThreadExtendedInfo() { void ThreadGDBRemote::WillResume(StateType resume_state) { int signo = GetResumeSignal(); const lldb::user_id_t tid = GetProtocolID(); - Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD)); + Log *log = GetLog(GDBRLog::Thread); LLDB_LOGF(log, "Resuming thread: %4.4" PRIx64 " with state: %s.", tid, StateAsCString(resume_state)); @@ -346,3 +346,23 @@ bool ThreadGDBRemote::CalculateStopInfo() { ->CalculateThreadStopInfo(this); return false; } + +llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> +ThreadGDBRemote::GetSiginfo(size_t max_size) const { + ProcessSP process_sp(GetProcess()); + if (!process_sp) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "no process"); + ProcessGDBRemote *gdb_process = + static_cast<ProcessGDBRemote *>(process_sp.get()); + if (!gdb_process->m_gdb_comm.GetQXferSigInfoReadSupported()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "qXfer:siginfo:read not supported"); + + llvm::Expected<std::string> response = + gdb_process->m_gdb_comm.ReadExtFeature("siginfo", ""); + if (!response) + return response.takeError(); + + return llvm::MemoryBuffer::getMemBufferCopy(response.get()); +} diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index b7d75021c062..fb83c74fd2c5 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -90,6 +90,9 @@ public: StructuredData::ObjectSP FetchThreadExtendedInfo() override; + llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> + GetSiginfo(size_t max_size) const override; + protected: friend class ProcessGDBRemote; diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp index cb21a3e7e65f..5eb7cb0e6a5c 100644 --- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp +++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp @@ -164,9 +164,6 @@ Status ScriptedProcess::DoLaunch(Module *exe_module, SetPrivateState(eStateStopped); - UpdateThreadListIfNeeded(); - GetThreadList(); - return {}; } @@ -225,8 +222,8 @@ bool ScriptedProcess::IsAlive() { size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { if (!m_interpreter) - return GetInterface().ErrorWithMessage<size_t>(LLVM_PRETTY_FUNCTION, - "No interpreter.", error); + return ScriptedInterface::ErrorWithMessage<size_t>( + LLVM_PRETTY_FUNCTION, "No interpreter.", error); lldb::DataExtractorSP data_extractor_sp = GetInterface().ReadMemoryAtAddress(addr, size, error); @@ -238,7 +235,7 @@ size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, 0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder()); if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET) - return GetInterface().ErrorWithMessage<size_t>( + return ScriptedInterface::ErrorWithMessage<size_t>( LLVM_PRETTY_FUNCTION, "Failed to copy read memory to buffer.", error); return size; @@ -296,7 +293,7 @@ bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list, ScriptLanguage language = m_interpreter->GetLanguage(); if (language != eScriptLanguagePython) - return GetInterface().ErrorWithMessage<bool>( + return ScriptedInterface::ErrorWithMessage<bool>( LLVM_PRETTY_FUNCTION, llvm::Twine("ScriptInterpreter language (" + llvm::Twine(m_interpreter->LanguageToString(language)) + @@ -304,19 +301,57 @@ bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list, .str(), error); - lldb::ThreadSP thread_sp; - thread_sp = std::make_shared<ScriptedThread>(*this, error); + StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo(); + + if (!thread_info_sp) + return ScriptedInterface::ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, + "Couldn't fetch thread list from Scripted Process.", error); + + auto create_scripted_thread = + [this, &old_thread_list, &error, + &new_thread_list](ConstString key, StructuredData::Object *val) -> bool { + if (!val) + return ScriptedInterface::ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, "Invalid thread info object", error); + + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; + if (!llvm::to_integer(key.AsCString(), tid)) + return ScriptedInterface::ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, "Invalid thread id", error); + + if (ThreadSP thread_sp = + old_thread_list.FindThreadByID(tid, false /*=can_update*/)) { + // If the thread was already in the old_thread_list, + // just add it back to the new_thread_list. + new_thread_list.AddThread(thread_sp); + return true; + } + + auto thread_or_error = ScriptedThread::Create(*this, val->GetAsGeneric()); + + if (!thread_or_error) + return ScriptedInterface::ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, toString(thread_or_error.takeError()), error); + + ThreadSP thread_sp = thread_or_error.get(); + lldbassert(thread_sp && "Couldn't initialize scripted thread."); + + RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext(); + if (!reg_ctx_sp) + return ScriptedInterface::ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, + llvm::Twine("Invalid Register Context for thread " + + llvm::Twine(key.AsCString())) + .str(), + error); - if (!thread_sp || error.Fail()) - return GetInterface().ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION, - error.AsCString(), error); + new_thread_list.AddThread(thread_sp); - RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext(); - if (!reg_ctx_sp) - return GetInterface().ErrorWithMessage<bool>( - LLVM_PRETTY_FUNCTION, "Invalid Register Context", error); + return true; + }; - new_thread_list.AddThread(thread_sp); + thread_info_sp->ForEach(create_scripted_thread); return new_thread_list.GetSize(false) > 0; } @@ -324,7 +359,6 @@ bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list, void ScriptedProcess::RefreshStateAfterStop() { // Let all threads recover from stopping and do any clean up based on the // previous thread state (if any). - m_thread_list.RefreshStateAfterStop(); } bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) { diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp index 959b8c581885..b6cbb62fd6e6 100644 --- a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp +++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp @@ -28,44 +28,60 @@ void ScriptedThread::CheckInterpreterAndScriptObject() const { lldbassert(GetInterface() && "Invalid Scripted Thread Interface."); } -ScriptedThread::ScriptedThread(ScriptedProcess &process, Status &error) - : Thread(process, LLDB_INVALID_THREAD_ID), m_scripted_process(process) { - if (!process.IsValid()) { - error.SetErrorString("Invalid scripted process"); - return; - } +llvm::Expected<std::shared_ptr<ScriptedThread>> +ScriptedThread::Create(ScriptedProcess &process, + StructuredData::Generic *script_object) { + if (!process.IsValid()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Invalid scripted process."); process.CheckInterpreterAndScriptObject(); - auto scripted_thread_interface = GetInterface(); - if (!scripted_thread_interface) { - error.SetErrorString("Failed to get scripted thread interface."); - return; - } - - llvm::Optional<std::string> class_name = - process.GetInterface().GetScriptedThreadPluginName(); - if (!class_name || class_name->empty()) { - error.SetErrorString("Failed to get scripted thread class name."); - return; + auto scripted_thread_interface = + process.GetInterface().CreateScriptedThreadInterface(); + if (!scripted_thread_interface) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Failed to create scripted thread interface."); + + llvm::StringRef thread_class_name; + if (!script_object) { + llvm::Optional<std::string> class_name = + process.GetInterface().GetScriptedThreadPluginName(); + if (!class_name || class_name->empty()) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Failed to get scripted thread class name."); + thread_class_name = *class_name; } ExecutionContext exe_ctx(process); - - StructuredData::GenericSP object_sp = + StructuredData::GenericSP owned_script_object_sp = scripted_thread_interface->CreatePluginObject( - class_name->c_str(), exe_ctx, - process.m_scripted_process_info.GetArgsSP()); - if (!object_sp || !object_sp->IsValid()) { - error.SetErrorString("Failed to create valid script object"); - return; - } + thread_class_name, exe_ctx, + process.m_scripted_process_info.GetArgsSP(), script_object); - m_script_object_sp = object_sp; + if (!owned_script_object_sp) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Failed to create script object."); + if (!owned_script_object_sp->IsValid()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Created script object is invalid."); - SetID(scripted_thread_interface->GetThreadID()); + lldb::tid_t tid = scripted_thread_interface->GetThreadID(); + + return std::make_shared<ScriptedThread>(process, scripted_thread_interface, + tid, owned_script_object_sp); } +ScriptedThread::ScriptedThread(ScriptedProcess &process, + ScriptedThreadInterfaceSP interface_sp, + lldb::tid_t tid, + StructuredData::GenericSP script_object_sp) + : Thread(process, tid), m_scripted_process(process), + m_scripted_thread_interface_sp(interface_sp), + m_script_object_sp(script_object_sp) {} + ScriptedThread::~ScriptedThread() { DestroyThread(); } const char *ScriptedThread::GetName() { @@ -137,6 +153,11 @@ bool ScriptedThread::CalculateStopInfo() { StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason(); Status error; + if (!dict_sp) + return GetInterface()->ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stop info.", error, + LIBLLDB_LOG_THREAD); + lldb::StopInfoSP stop_info_sp; lldb::StopReason stop_reason_type; @@ -150,12 +171,12 @@ bool ScriptedThread::CalculateStopInfo() { if (!dict_sp->GetValueForKeyAsDictionary("data", data_dict)) return GetInterface()->ErrorWithMessage<bool>( LLVM_PRETTY_FUNCTION, - "Couldn't find value for key 'type' in stop reason dictionary.", error, + "Couldn't find value for key 'data' in stop reason dictionary.", error, LIBLLDB_LOG_THREAD); switch (stop_reason_type) { case lldb::eStopReasonNone: - break; + return true; case lldb::eStopReasonBreakpoint: { lldb::break_id_t break_id; data_dict->GetValueForKeyAsInteger("break_id", break_id, @@ -172,6 +193,13 @@ bool ScriptedThread::CalculateStopInfo() { stop_info_sp = StopInfo::CreateStopReasonWithSignal(*this, signal, description.data()); } break; + case lldb::eStopReasonException: { + llvm::StringRef description; + data_dict->GetValueForKeyAsString("desc", description); + + stop_info_sp = + StopInfo::CreateStopReasonWithException(*this, description.data()); + } break; default: return GetInterface()->ErrorWithMessage<bool>( LLVM_PRETTY_FUNCTION, @@ -181,6 +209,9 @@ bool ScriptedThread::CalculateStopInfo() { error, LIBLLDB_LOG_THREAD); } + if (!stop_info_sp) + return false; + SetStopInfo(stop_info_sp); return true; } @@ -190,7 +221,7 @@ void ScriptedThread::RefreshStateAfterStop() { } lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const { - return m_scripted_process.GetInterface().GetScriptedThreadInterface(); + return m_scripted_thread_interface_sp; } std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() { diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.h b/lldb/source/Plugins/Process/scripted/ScriptedThread.h index cdcd543702a4..8d8a7c2a3df9 100644 --- a/lldb/source/Plugins/Process/scripted/ScriptedThread.h +++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.h @@ -25,11 +25,18 @@ class ScriptedProcess; namespace lldb_private { class ScriptedThread : public lldb_private::Thread { + public: - ScriptedThread(ScriptedProcess &process, Status &error); + ScriptedThread(ScriptedProcess &process, + lldb::ScriptedThreadInterfaceSP interface_sp, lldb::tid_t tid, + StructuredData::GenericSP script_object_sp = nullptr); ~ScriptedThread() override; + static llvm::Expected<std::shared_ptr<ScriptedThread>> + Create(ScriptedProcess &process, + StructuredData::Generic *script_object = nullptr); + lldb::RegisterContextSP GetRegisterContext() override; lldb::RegisterContextSP @@ -59,8 +66,9 @@ private: std::shared_ptr<DynamicRegisterInfo> GetDynamicRegisterInfo(); const ScriptedProcess &m_scripted_process; + lldb::ScriptedThreadInterfaceSP m_scripted_thread_interface_sp = nullptr; + lldb_private::StructuredData::GenericSP m_script_object_sp = nullptr; std::shared_ptr<DynamicRegisterInfo> m_register_info_sp = nullptr; - lldb_private::StructuredData::ObjectSP m_script_object_sp = nullptr; }; } // namespace lldb_private |