diff options
Diffstat (limited to 'lldb/source/Plugins/Process')
35 files changed, 737 insertions, 338 deletions
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp index 8b6f9fbc33c3..4313d27e11e9 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -8,8 +8,7 @@ #include "NativeProcessNetBSD.h" - - +#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #include "lldb/Host/HostProcess.h" #include "lldb/Host/common/NativeRegisterContext.h" @@ -99,6 +98,17 @@ NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate, Info.GetArchitecture(), mainloop)); + // Enable event reporting + ptrace_event_t events; + status = PtraceWrapper(PT_GET_EVENT_MASK, pid, &events, sizeof(events)); + if (status.Fail()) + return status.ToError(); + // TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN? + events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT; + status = PtraceWrapper(PT_SET_EVENT_MASK, pid, &events, sizeof(events)); + if (status.Fail()) + return status.ToError(); + status = process_up->ReinitializeThreads(); if (status.Fail()) return status.ToError(); @@ -211,17 +221,32 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { return; } + NativeThreadNetBSD* thread = nullptr; + if (info.psi_lwpid > 0) { + for (const auto &t : m_threads) { + if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) { + thread = static_cast<NativeThreadNetBSD *>(t.get()); + break; + } + static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason(); + } + if (!thread) + LLDB_LOG(log, + "thread not found in m_threads, pid = {0}, LWP = {1}", pid, + info.psi_lwpid); + } + switch (info.psi_siginfo.si_code) { case TRAP_BRKPT: - for (const auto &thread : m_threads) { - static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByBreakpoint(); - FixupBreakpointPCAsNeeded(static_cast<NativeThreadNetBSD &>(*thread)); + if (thread) { + thread->SetStoppedByBreakpoint(); + FixupBreakpointPCAsNeeded(*thread); } SetState(StateType::eStateStopped, true); break; case TRAP_TRACE: - for (const auto &thread : m_threads) - static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByTrace(); + if (thread) + thread->SetStoppedByTrace(); SetState(StateType::eStateStopped, true); break; case TRAP_EXEC: { @@ -238,54 +263,66 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec(); SetState(StateType::eStateStopped, true); } break; - case TRAP_DBREG: { - // Find the thread. - NativeThreadNetBSD* thread = nullptr; - for (const auto &t : m_threads) { - if (t->GetID() == info.psi_lwpid) { - thread = static_cast<NativeThreadNetBSD *>(t.get()); + case TRAP_LWP: { + ptrace_state_t pst; + Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst)); + if (error.Fail()) { + SetState(StateType::eStateInvalid); + return; + } + + switch (pst.pe_report_event) { + case PTRACE_LWP_CREATE: { + LLDB_LOG(log, + "monitoring new thread, pid = {0}, LWP = {1}", pid, + pst.pe_lwp); + NativeThreadNetBSD& t = AddThread(pst.pe_lwp); + error = t.CopyWatchpointsFrom( + static_cast<NativeThreadNetBSD &>(*GetCurrentThread())); + if (error.Fail()) { + LLDB_LOG(log, + "failed to copy watchpoints to new thread {0}: {1}", + pst.pe_lwp, error); + SetState(StateType::eStateInvalid); + return; + } + } break; + case PTRACE_LWP_EXIT: + LLDB_LOG(log, + "removing exited thread, pid = {0}, LWP = {1}", pid, + pst.pe_lwp); + RemoveThread(pst.pe_lwp); break; - } } - if (!thread) { - LLDB_LOG(log, - "thread not found in m_threads, pid = {0}, LWP = {1}", - GetID(), info.psi_lwpid); - break; + + error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void*>(1), 0); + if (error.Fail()) { + SetState(StateType::eStateInvalid); + return; } + } break; + case TRAP_DBREG: { + if (!thread) + break; - // If a watchpoint was hit, report it + auto ®ctx = static_cast<NativeRegisterContextNetBSD &>( + thread->GetRegisterContext()); uint32_t wp_index = LLDB_INVALID_INDEX32; - Status error = thread->GetRegisterContext().GetWatchpointHitIndex( - wp_index, (uintptr_t)info.psi_siginfo.si_addr); + Status error = regctx.GetWatchpointHitIndex(wp_index, + (uintptr_t)info.psi_siginfo.si_addr); if (error.Fail()) LLDB_LOG(log, "received error while checking for watchpoint hits, pid = " - "{0}, LWP = {1}, error = {2}", - GetID(), info.psi_lwpid, error); + "{0}, LWP = {1}, error = {2}", pid, info.psi_lwpid, error); if (wp_index != LLDB_INVALID_INDEX32) { - for (const auto &thread : m_threads) - static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByWatchpoint( - wp_index); + thread->SetStoppedByWatchpoint(wp_index); + regctx.ClearWatchpointHit(wp_index); SetState(StateType::eStateStopped, true); break; } - // If a breakpoint was hit, report it - uint32_t bp_index = LLDB_INVALID_INDEX32; - error = thread->GetRegisterContext().GetHardwareBreakHitIndex( - bp_index, (uintptr_t)info.psi_siginfo.si_addr); - if (error.Fail()) - LLDB_LOG(log, - "received error while checking for hardware " - "breakpoint hits, pid = {0}, LWP = {1}, error = {2}", - GetID(), info.psi_lwpid, error); - if (bp_index != LLDB_INVALID_INDEX32) { - for (const auto &thread : m_threads) - static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByBreakpoint(); - SetState(StateType::eStateStopped, true); - break; - } + thread->SetStoppedByTrace(); + SetState(StateType::eStateStopped, true); } break; } } @@ -295,9 +332,14 @@ void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) { const auto siginfo_err = PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info)); - for (const auto &thread : m_threads) { - static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal( - info.psi_siginfo.si_signo, &info.psi_siginfo); + for (const auto &abs_thread : m_threads) { + NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread); + assert(info.psi_lwpid >= 0); + if (info.psi_lwpid == 0 || + static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID()) + thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo); + else + thread.SetStoppedWithNoReason(); } SetState(StateType::eStateStopped, true); } @@ -325,68 +367,137 @@ Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, return error; } +static llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo( + const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads, + const ResumeActionList &resume_actions) { + // We need to account for three possible scenarios: + // 1. no signal being sent. + // 2. a signal being sent to one thread. + // 3. a signal being sent to the whole process. + + // Count signaled threads. While at it, determine which signal is being sent + // and ensure there's only one. + size_t signaled_threads = 0; + int signal = LLDB_INVALID_SIGNAL_NUMBER; + lldb::tid_t signaled_lwp; + for (const auto &thread : threads) { + assert(thread && "thread list should not contain NULL threads"); + const ResumeAction *action = + resume_actions.GetActionForThread(thread->GetID(), true); + if (action) { + if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) { + signaled_threads++; + if (action->signal != signal) { + if (signal != LLDB_INVALID_SIGNAL_NUMBER) + return Status("NetBSD does not support passing multiple signals " + "simultaneously") + .ToError(); + signal = action->signal; + signaled_lwp = thread->GetID(); + } + } + } + } + + if (signaled_threads == 0) { + ptrace_siginfo_t siginfo; + siginfo.psi_siginfo.si_signo = LLDB_INVALID_SIGNAL_NUMBER; + return siginfo; + } + + if (signaled_threads > 1 && signaled_threads < threads.size()) + return Status("NetBSD does not support passing signal to 1<i<all threads") + .ToError(); + + ptrace_siginfo_t siginfo; + siginfo.psi_siginfo.si_signo = signal; + siginfo.psi_siginfo.si_code = SI_USER; + siginfo.psi_siginfo.si_pid = getpid(); + siginfo.psi_siginfo.si_uid = getuid(); + if (signaled_threads == 1) + siginfo.psi_lwpid = signaled_lwp; + else // signal for the whole process + siginfo.psi_lwpid = 0; + return siginfo; +} + Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); LLDB_LOG(log, "pid {0}", GetID()); - const auto &thread = m_threads[0]; - const ResumeAction *const action = - resume_actions.GetActionForThread(thread->GetID(), true); + Status ret; - if (action == nullptr) { - LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), - thread->GetID()); - return Status(); - } + Expected<ptrace_siginfo_t> siginfo = + ComputeSignalInfo(m_threads, resume_actions); + if (!siginfo) + return Status(siginfo.takeError()); - Status error; - int signal = - action->signal != LLDB_INVALID_SIGNAL_NUMBER ? action->signal : 0; - - switch (action->state) { - case eStateRunning: { - // Run the thread, possibly feeding it the signal. - error = NativeProcessNetBSD::PtraceWrapper(PT_CONTINUE, GetID(), (void *)1, - signal); - if (!error.Success()) - return error; - for (const auto &thread : m_threads) - static_cast<NativeThreadNetBSD &>(*thread).SetRunning(); - SetState(eStateRunning, true); - break; - } - case eStateStepping: - // Run the thread, possibly feeding it the signal. - error = NativeProcessNetBSD::PtraceWrapper(PT_STEP, GetID(), (void *)1, - signal); - if (!error.Success()) - return error; - for (const auto &thread : m_threads) - static_cast<NativeThreadNetBSD &>(*thread).SetStepping(); - SetState(eStateStepping, true); - break; + for (const auto &abs_thread : m_threads) { + assert(abs_thread && "thread list should not contain NULL threads"); + NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread); - case eStateSuspended: - case eStateStopped: - llvm_unreachable("Unexpected state"); + const ResumeAction *action = + resume_actions.GetActionForThread(thread.GetID(), true); + // we need to explicit issue suspend requests, so it is simpler to map it + // into proper action + ResumeAction suspend_action{thread.GetID(), eStateSuspended, + LLDB_INVALID_SIGNAL_NUMBER}; - default: - return Status("NativeProcessNetBSD::%s (): unexpected state %s specified " - "for pid %" PRIu64 ", tid %" PRIu64, - __FUNCTION__, StateAsCString(action->state), GetID(), - thread->GetID()); + if (action == nullptr) { + LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), + thread.GetID()); + action = &suspend_action; + } + + LLDB_LOG( + log, + "processing resume action state {0} signal {1} for pid {2} tid {3}", + action->state, action->signal, GetID(), thread.GetID()); + + switch (action->state) { + case eStateRunning: + ret = thread.Resume(); + break; + case eStateStepping: + ret = thread.SingleStep(); + break; + case eStateSuspended: + case eStateStopped: + if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) + return Status("Passing signal to suspended thread unsupported"); + + ret = thread.Suspend(); + break; + + default: + return Status("NativeProcessNetBSD::%s (): unexpected state %s specified " + "for pid %" PRIu64 ", tid %" PRIu64, + __FUNCTION__, StateAsCString(action->state), GetID(), + thread.GetID()); + } + + if (!ret.Success()) + return ret; } - return Status(); + int signal = 0; + if (siginfo->psi_siginfo.si_signo != LLDB_INVALID_SIGNAL_NUMBER) { + ret = PtraceWrapper(PT_SET_SIGINFO, GetID(), &siginfo.get(), + sizeof(*siginfo)); + if (!ret.Success()) + return ret; + signal = siginfo->psi_siginfo.si_signo; + } + + ret = PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), + signal); + if (ret.Success()) + SetState(eStateRunning, true); + return ret; } Status NativeProcessNetBSD::Halt() { - Status error; - - if (kill(GetID(), SIGSTOP) != 0) - error.SetErrorToErrno(); - - return error; + return PtraceWrapper(PT_STOP, GetID()); } Status NativeProcessNetBSD::Detach() { @@ -411,6 +522,10 @@ Status NativeProcessNetBSD::Signal(int signo) { return error; } +Status NativeProcessNetBSD::Interrupt() { + return PtraceWrapper(PT_STOP, GetID()); +} + Status NativeProcessNetBSD::Kill() { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); LLDB_LOG(log, "pid {0}", GetID()); @@ -650,10 +765,10 @@ bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) { } NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); + assert(thread_id > 0); assert(!HasThreadNoLock(thread_id) && "attempted to add a thread by id that already exists"); @@ -665,6 +780,22 @@ NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) { return static_cast<NativeThreadNetBSD &>(*m_threads.back()); } +void NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id); + + assert(thread_id > 0); + assert(HasThreadNoLock(thread_id) && + "attempted to remove a thread that does not exist"); + + for (auto it = m_threads.begin(); it != m_threads.end(); ++it) { + if ((*it)->GetID() == thread_id) { + m_threads.erase(it); + break; + } + } +} + Status NativeProcessNetBSD::Attach() { // Attach to the requested process. // An attach will cause the thread to stop with a SIGSTOP. @@ -783,15 +914,23 @@ Status NativeProcessNetBSD::ReinitializeThreads() { m_threads.clear(); // Initialize new thread +#ifdef PT_LWPSTATUS + struct ptrace_lwpstatus info = {}; + int op = PT_LWPNEXT; +#else struct ptrace_lwpinfo info = {}; - Status error = PtraceWrapper(PT_LWPINFO, GetID(), &info, sizeof(info)); + int op = PT_LWPINFO; +#endif + + Status error = PtraceWrapper(op, GetID(), &info, sizeof(info)); + if (error.Fail()) { return error; } // Reinitialize from scratch threads and register them in process while (info.pl_lwpid != 0) { AddThread(info.pl_lwpid); - error = PtraceWrapper(PT_LWPINFO, GetID(), &info, sizeof(info)); + error = PtraceWrapper(op, GetID(), &info, sizeof(info)); if (error.Fail()) { return error; } diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h index 4e7f0a1c13ab..6a06773f40a8 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h @@ -47,6 +47,8 @@ public: Status Signal(int signo) override; + Status Interrupt() override; + Status Kill() override; Status GetMemoryRegionInfo(lldb::addr_t load_addr, @@ -98,6 +100,7 @@ private: bool HasThreadNoLock(lldb::tid_t thread_id); NativeThreadNetBSD &AddThread(lldb::tid_t thread_id); + void RemoveThread(lldb::tid_t thread_id); void MonitorCallback(lldb::pid_t pid, int signal); void MonitorExited(lldb::pid_t pid, WaitStatus status); diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp index 3a9caaad74c8..a8afa0b20305 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp @@ -8,6 +8,8 @@ #include "NativeRegisterContextNetBSD.h" +#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" + #include "lldb/Host/common/NativeProcessProtocol.h" using namespace lldb_private; diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h index f5dd0c33b677..13e023d856d2 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h @@ -11,12 +11,13 @@ #include "lldb/Host/common/NativeThreadProtocol.h" -#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" namespace lldb_private { namespace process_netbsd { +class NativeProcessNetBSD; + class NativeRegisterContextNetBSD : public NativeRegisterContextRegisterInfo { public: NativeRegisterContextNetBSD(NativeThreadProtocol &native_thread, @@ -30,6 +31,10 @@ public: static NativeRegisterContextNetBSD * CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); + virtual Status + CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) = 0; + + virtual Status ClearWatchpointHit(uint32_t wp_index) = 0; protected: Status DoRegisterSet(int req, void *buf); diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp index 6cc2810fa235..05a35401da46 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp @@ -84,13 +84,71 @@ static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - k_num_gpr_registers_x86_64, "g_gpr_regnums_x86_64 has wrong number of register infos"); +// x86 64-bit floating point registers. +static const uint32_t g_fpu_regnums_x86_64[] = { + lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, + lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, + lldb_foseg_x86_64, lldb_fooff_x86_64, lldb_mxcsr_x86_64, + lldb_mxcsrmask_x86_64, lldb_st0_x86_64, lldb_st1_x86_64, + lldb_st2_x86_64, lldb_st3_x86_64, lldb_st4_x86_64, + lldb_st5_x86_64, lldb_st6_x86_64, lldb_st7_x86_64, + lldb_mm0_x86_64, lldb_mm1_x86_64, lldb_mm2_x86_64, + lldb_mm3_x86_64, lldb_mm4_x86_64, lldb_mm5_x86_64, + lldb_mm6_x86_64, lldb_mm7_x86_64, lldb_xmm0_x86_64, + lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64, + lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64, + lldb_xmm7_x86_64, lldb_xmm8_x86_64, lldb_xmm9_x86_64, + lldb_xmm10_x86_64, lldb_xmm11_x86_64, lldb_xmm12_x86_64, + lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - + 1 == + k_num_fpr_registers_x86_64, + "g_fpu_regnums_x86_64 has wrong number of register infos"); + +// x86 64-bit registers available via XState. +static const uint32_t g_xstate_regnums_x86_64[] = { + lldb_ymm0_x86_64, lldb_ymm1_x86_64, lldb_ymm2_x86_64, lldb_ymm3_x86_64, + lldb_ymm4_x86_64, lldb_ymm5_x86_64, lldb_ymm6_x86_64, lldb_ymm7_x86_64, + lldb_ymm8_x86_64, lldb_ymm9_x86_64, lldb_ymm10_x86_64, lldb_ymm11_x86_64, + lldb_ymm12_x86_64, lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64, + // Note: we currently do not provide them but this is needed to avoid + // unnamed groups in SBFrame::GetRegisterContext(). + lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64, + lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_xstate_regnums_x86_64) / sizeof(g_xstate_regnums_x86_64[0])) - + 1 == + k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64, + "g_xstate_regnums_x86_64 has wrong number of register infos"); + +// x86 debug registers. +static const uint32_t g_dbr_regnums_x86_64[] = { + lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64, + lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) - + 1 == + k_num_dbr_registers_x86_64, + "g_dbr_regnums_x86_64 has wrong number of register infos"); + // Number of register sets provided by this context. -enum { k_num_extended_register_sets = 2, k_num_register_sets = 4 }; +enum { k_num_register_sets = 4 }; // Register sets for x86 64-bit. static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64}, + {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, + g_fpu_regnums_x86_64}, + {"Extended State Registers", "xstate", + k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64, + g_xstate_regnums_x86_64}, + {"Debug Registers", "dbr", k_num_dbr_registers_x86_64, + g_dbr_regnums_x86_64}, }; #define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize()) @@ -667,11 +725,6 @@ Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues( ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize()); dst += GetRegisterInfoInterface().GetGPRSize(); - RegisterValue value((uint64_t)-1); - const RegisterInfo *reg_info = - GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax"); - if (reg_info == nullptr) - reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax"); return error; } @@ -795,10 +848,10 @@ Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex( if (!is_vacant) return Status("Watchpoint index not vacant"); - RegisterValue reg_value; const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(lldb_dr7_x86_64); - error = ReadRegister(reg_info_dr7, reg_value); + RegisterValue dr7_value; + error = ReadRegister(reg_info_dr7, dr7_value); if (error.Fail()) return error; @@ -816,16 +869,28 @@ Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex( uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; + uint64_t control_bits = dr7_value.GetAsUInt64() & ~bit_mask; control_bits |= enable_bit | rw_bits | size_bits; const RegisterInfo *const reg_info_drN = GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index); - error = WriteRegister(reg_info_drN, RegisterValue(addr)); + RegisterValue drN_value; + error = ReadRegister(reg_info_drN, drN_value); if (error.Fail()) return error; + // clear dr6 if address or bits changed (i.e. we're not reenabling the same + // watchpoint) + if (drN_value.GetAsUInt64() != addr || + (dr7_value.GetAsUInt64() & bit_mask) != (rw_bits | size_bits)) { + ClearWatchpointHit(wp_index); + + error = WriteRegister(reg_info_drN, RegisterValue(addr)); + if (error.Fail()) + return error; + } + error = WriteRegister(reg_info_dr7, RegisterValue(control_bits)); if (error.Fail()) return error; @@ -839,32 +904,36 @@ bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint( if (wp_index >= NumSupportedHardwareWatchpoints()) return false; + // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0-1, 2-3, 4-5 + // or 6-7 of the debug control register (DR7) + const RegisterInfo *const reg_info_dr7 = + GetRegisterInfoAtIndex(lldb_dr7_x86_64); RegisterValue reg_value; + Status error = ReadRegister(reg_info_dr7, reg_value); + if (error.Fail()) + return false; + uint64_t bit_mask = 0x3 << (2 * wp_index); + uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of + return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success(); +} + +Status NativeRegisterContextNetBSD_x86_64::ClearWatchpointHit(uint32_t wp_index) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Status("Watchpoint index out of range"); + + // for watchpoints 0, 1, 2, or 3, respectively, check bits 0, 1, 2, or 3 of // the debug status register (DR6) const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(lldb_dr6_x86_64); + RegisterValue reg_value; Status error = ReadRegister(reg_info_dr6, reg_value); if (error.Fail()) - return false; + return error; + uint64_t bit_mask = 1 << wp_index; uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; - error = WriteRegister(reg_info_dr6, RegisterValue(status_bits)); - if (error.Fail()) - return false; - - // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19}, - // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register - // (DR7) - const RegisterInfo *const reg_info_dr7 = - GetRegisterInfoAtIndex(lldb_dr7_x86_64); - error = ReadRegister(reg_info_dr7, reg_value); - if (error.Fail()) - return false; - bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success(); + return WriteRegister(reg_info_dr6, RegisterValue(status_bits)); } Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() { @@ -930,4 +999,19 @@ uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() { return 4; } +Status NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom( + NativeRegisterContextNetBSD &source) { + auto &r_source = static_cast<NativeRegisterContextNetBSD_x86_64&>(source); + Status res = r_source.ReadRegisterSet(DBRegSet); + if (!res.Fail()) { + // copy dbregs only if any watchpoints were set + if ((r_source.m_dbr_x86_64.dr[7] & 0xFF) == 0) + return res; + + m_dbr_x86_64 = r_source.m_dbr_x86_64; + res = WriteRegisterSet(DBRegSet); + } + return res; +} + #endif // defined(__x86_64__) diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h index 0fed16542a95..54b8a806267f 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h @@ -58,6 +58,8 @@ public: bool ClearHardwareWatchpoint(uint32_t wp_index) override; + Status ClearWatchpointHit(uint32_t wp_index) override; + Status ClearAllHardwareWatchpoints() override; Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, @@ -71,9 +73,12 @@ public: uint32_t NumSupportedHardwareWatchpoints() override; + Status + CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) override; + private: // Private member types. - enum { GPRegSet, FPRegSet, DBRegSet, XStateRegSet }; + enum { GPRegSet, FPRegSet, XStateRegSet, DBRegSet }; // Private member variables. struct reg m_gpr_x86_64; diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp index e25975c93446..dd2745d9330e 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp @@ -16,9 +16,20 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/State.h" +#include "llvm/Support/Errno.h" + +// clang-format off +#include <sys/types.h> +#include <sys/ptrace.h> +// clang-format on #include <sstream> +// clang-format off +#include <sys/types.h> +#include <sys/sysctl.h> +// clang-format on + using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_netbsd; @@ -30,6 +41,38 @@ NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process, NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this) ), m_stop_description() {} +Status NativeThreadNetBSD::Resume() { + Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(), + nullptr, GetID()); + if (!ret.Success()) + return ret; + ret = NativeProcessNetBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(), + nullptr, GetID()); + if (ret.Success()) + SetRunning(); + return ret; +} + +Status NativeThreadNetBSD::SingleStep() { + Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(), + nullptr, GetID()); + if (!ret.Success()) + return ret; + ret = NativeProcessNetBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(), + nullptr, GetID()); + if (ret.Success()) + SetStepping(); + return ret; +} + +Status NativeThreadNetBSD::Suspend() { + Status ret = NativeProcessNetBSD::PtraceWrapper(PT_SUSPEND, m_process.GetID(), + nullptr, GetID()); + if (ret.Success()) + SetStopped(); + return ret; +} + void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo, const siginfo_t *info) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); @@ -89,6 +132,13 @@ void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) { m_stop_info.details.signal.signo = SIGTRAP; } +void NativeThreadNetBSD::SetStoppedWithNoReason() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_info.details.signal.signo = 0; +} + void NativeThreadNetBSD::SetStopped() { const StateType new_state = StateType::eStateStopped; m_state = new_state; @@ -105,7 +155,49 @@ void NativeThreadNetBSD::SetStepping() { m_stop_info.reason = StopReason::eStopReasonNone; } -std::string NativeThreadNetBSD::GetName() { return std::string(""); } +std::string NativeThreadNetBSD::GetName() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + +#ifdef PT_LWPSTATUS + struct ptrace_lwpstatus info = {}; + info.pl_lwpid = m_tid; + Status error = NativeProcessNetBSD::PtraceWrapper( + PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info)); + if (error.Fail()) { + return ""; + } + return info.pl_name; +#else + std::vector<struct kinfo_lwp> infos; + int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()), + sizeof(struct kinfo_lwp), 0}; + size_t size; + + if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) { + LLDB_LOG(log, "sysctl() for LWP info size failed: {0}", + llvm::sys::StrError()); + return ""; + } + + mib[4] = size / sizeof(size_t); + infos.resize(size / sizeof(struct kinfo_lwp)); + + if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) { + LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError()); + return ""; + } + + size_t nlwps = size / sizeof(struct kinfo_lwp); + for (size_t i = 0; i < nlwps; i++) { + if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) { + return infos[i].l_name; + } + } + + LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid); + return ""; +#endif +} lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } @@ -140,9 +232,9 @@ bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, llvm_unreachable("unhandled StateType!"); } -NativeRegisterContext& NativeThreadNetBSD::GetRegisterContext() { +NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { assert(m_reg_context_up); -return *m_reg_context_up; + return *m_reg_context_up; } Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, @@ -203,3 +295,13 @@ Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { return Status("Clearing hardware breakpoint failed."); } + +Status NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { + Status s = GetRegisterContext().CopyHardwareWatchpointsFrom( + source.GetRegisterContext()); + if (!s.Fail()) { + m_watchpoint_index_map = source.m_watchpoint_index_map; + m_hw_break_index_map = source.m_hw_break_index_map; + } + return s; +} diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h index 015d8995db34..89b61ef86722 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h @@ -11,6 +11,8 @@ #include "lldb/Host/common/NativeThreadProtocol.h" +#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h" + #include <csignal> #include <map> #include <string> @@ -34,7 +36,7 @@ public: bool GetStopReason(ThreadStopInfo &stop_info, std::string &description) override; - NativeRegisterContext& GetRegisterContext() override; + NativeRegisterContextNetBSD &GetRegisterContext() override; Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) override; @@ -48,19 +50,26 @@ public: private: // Interface for friend classes + Status Resume(); + Status SingleStep(); + Status Suspend(); + void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); void SetStoppedByBreakpoint(); void SetStoppedByTrace(); void SetStoppedByExec(); void SetStoppedByWatchpoint(uint32_t wp_index); + void SetStoppedWithNoReason(); void SetStopped(); void SetRunning(); void SetStepping(); + Status CopyWatchpointsFrom(NativeThreadNetBSD& source); + // Member Variables lldb::StateType m_state; ThreadStopInfo m_stop_info; - std::unique_ptr<NativeRegisterContext> m_reg_context_up; + std::unique_ptr<NativeRegisterContextNetBSD> m_reg_context_up; std::string m_stop_description; using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>; WatchpointIndexMap m_watchpoint_index_map; diff --git a/lldb/source/Plugins/Process/POSIX/CrashReason.cpp b/lldb/source/Plugins/Process/POSIX/CrashReason.cpp index 9678e48436e7..b872269fdfe1 100644 --- a/lldb/source/Plugins/Process/POSIX/CrashReason.cpp +++ b/lldb/source/Plugins/Process/POSIX/CrashReason.cpp @@ -136,15 +136,15 @@ std::string GetCrashReasonString(CrashReason reason, const siginfo_t &info) { #if defined(si_lower) && defined(si_upper) if (reason == CrashReason::eBoundViolation) { str = "signal SIGSEGV"; - AppendBounds(str, reinterpret_cast<lldb::addr_t>(info.si_lower), - reinterpret_cast<lldb::addr_t>(info.si_upper), - reinterpret_cast<lldb::addr_t>(info.si_addr)); + AppendBounds(str, reinterpret_cast<uintptr_t>(info.si_lower), + reinterpret_cast<uintptr_t>(info.si_upper), + reinterpret_cast<uintptr_t>(info.si_addr)); return str; } #endif return GetCrashReasonString(reason, - reinterpret_cast<lldb::addr_t>(info.si_addr)); + reinterpret_cast<uintptr_t>(info.si_addr)); } std::string GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr) { diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 2ccbeacc4960..ee939b01d350 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -20,7 +20,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/ThreadPlanCallFunction.h" -#ifndef LLDB_DISABLE_POSIX +#if LLDB_ENABLE_POSIX #include <sys/mman.h> #else // define them diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp index 4ca33c248c6f..173e66904151 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp @@ -21,12 +21,6 @@ #include <memory> -// Support building against older versions of LLVM, this macro was added -// recently. -#ifndef LLVM_EXTENSION -#define LLVM_EXTENSION -#endif - #include "Utility/ARM_DWARF_Registers.h" #include "Utility/ARM_ehframe_Registers.h" @@ -1146,10 +1140,11 @@ bool RegisterContextDarwin_arm::ReadRegister(const RegisterInfo *reg_info, case gpr_sp: case gpr_lr: case gpr_pc: - case gpr_cpsr: value.SetUInt32(gpr.r[reg - gpr_r0]); break; - + case gpr_cpsr: + value.SetUInt32(gpr.cpsr); + break; case fpu_s0: case fpu_s1: case fpu_s2: diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp index b3ec24d8905d..fa5197cd6bf4 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp @@ -30,12 +30,6 @@ #include <sys/sysctl.h> #endif -// Support building against older versions of LLVM, this macro was added -// recently. -#ifndef LLVM_EXTENSION -#define LLVM_EXTENSION -#endif - #include "Utility/ARM64_DWARF_Registers.h" using namespace lldb; diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp index 873713fd8373..959b04700b17 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp @@ -19,12 +19,6 @@ #include <memory> -// Support building against older versions of LLVM, this macro was added -// recently. -#ifndef LLVM_EXTENSION -#define LLVM_EXTENSION -#endif - #include "RegisterContextDarwin_i386.h" using namespace lldb; diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp index 47758ce85eb2..22088a7d6448 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp @@ -21,12 +21,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" -// Support building against older versions of LLVM, this macro was added -// recently. -#ifndef LLVM_EXTENSION -#define LLVM_EXTENSION -#endif - #include "RegisterContextDarwin_x86_64.h" using namespace lldb; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h index 4a3b3c73fd6b..af3027afa73c 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h @@ -25,15 +25,18 @@ LLVM_EXTENSION offsetof(FPR, xsave) + \ LLVM_EXTENSION offsetof(XSAVE, ymmh[0]) + (32 * reg_index)) +// Guarantees BNDR/BNDC offsets do not overlap with YMM offsets. +#define GDB_REMOTE_OFFSET 128 + #define BNDR_OFFSET(reg_index) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR, xsave) + \ - LLVM_EXTENSION offsetof(XSAVE, mpxr[reg_index])) + LLVM_EXTENSION offsetof(XSAVE, mpxr[reg_index]) + GDB_REMOTE_OFFSET) #define BNDC_OFFSET(reg_index) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR, xsave) + \ - LLVM_EXTENSION offsetof(XSAVE, mpxc[reg_index])) + LLVM_EXTENSION offsetof(XSAVE, mpxc[reg_index]) + GDB_REMOTE_OFFSET) #ifdef DECLARE_REGISTER_INFOS_X86_64_STRUCT diff --git a/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h index 0d2149c83573..bfdd586d9ded 100644 --- a/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h @@ -294,7 +294,8 @@ enum { lldb_bndstatus_x86_64, k_last_mpxc_x86_64 = lldb_bndstatus_x86_64, - lldb_dr0_x86_64, + k_first_dbr_x86_64, + lldb_dr0_x86_64 = k_first_dbr_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64, @@ -302,6 +303,7 @@ enum { lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64, + k_last_dbr_x86_64 = lldb_dr7_x86_64, k_num_registers_x86_64, k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1, @@ -312,6 +314,7 @@ enum { k_num_fpr_registers_x86_64 + k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64, + k_num_dbr_registers_x86_64 = k_last_dbr_x86_64 - k_first_dbr_x86_64 + 1, }; } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 144ae103faa4..7cea013eea7f 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -31,6 +31,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/StreamString.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ScopedPrinter.h" @@ -49,7 +50,7 @@ #include <compression.h> #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB #include <zlib.h> #endif @@ -581,7 +582,7 @@ bool GDBRemoteCommunication::DecompressPacket() { } #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr && m_compression_type == CompressionType::ZlibDeflate) { @@ -1243,8 +1244,9 @@ Status GDBRemoteCommunication::StartDebugserverProcess( void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); } -void GDBRemoteCommunication::SetHistoryStream(llvm::raw_ostream *strm) { - m_history.SetStream(strm); +void GDBRemoteCommunication::SetPacketRecorder( + repro::PacketRecorder *recorder) { + m_history.SetRecorder(recorder); } llvm::Error diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index bb777a5c26a7..0b670018bd69 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -27,6 +27,9 @@ #include "lldb/lldb-public.h" namespace lldb_private { +namespace repro { +class PacketRecorder; +} namespace process_gdb_remote { enum GDBStoppointType { @@ -133,7 +136,8 @@ public: // fork/exec to avoid having to connect/accept void DumpHistory(Stream &strm); - void SetHistoryStream(llvm::raw_ostream *strm); + + void SetPacketRecorder(repro::PacketRecorder *recorder); static llvm::Error ConnectLocally(GDBRemoteCommunication &client, GDBRemoteCommunication &server); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index feb9f0589cee..b2f1ee527e8b 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -543,21 +543,24 @@ GDBRemoteCommunicationClient::SendThreadSpecificPacketAndWaitForResponse( // // Takes a valid thread ID because p needs to apply to a thread. bool GDBRemoteCommunicationClient::GetpPacketSupported(lldb::tid_t tid) { - if (m_supports_p == eLazyBoolCalculate) { - m_supports_p = eLazyBoolNo; - StreamString payload; - payload.PutCString("p0"); - StringExtractorGDBRemote response; - if (SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), - response, false) == - PacketResult::Success && - response.IsNormalResponse()) { - m_supports_p = eLazyBoolYes; - } - } + if (m_supports_p == eLazyBoolCalculate) + m_supports_p = GetThreadPacketSupported(tid, "p0"); return m_supports_p; } +LazyBool GDBRemoteCommunicationClient::GetThreadPacketSupported( + lldb::tid_t tid, llvm::StringRef packetStr) { + StreamString payload; + payload.PutCString(packetStr); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response, false) == PacketResult::Success && + response.IsNormalResponse()) { + return eLazyBoolYes; + } + return eLazyBoolNo; +} + StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() { // Get information on all threads at one using the "jThreadsInfo" packet StructuredData::ObjectSP object_sp; @@ -1042,7 +1045,7 @@ void GDBRemoteCommunicationClient::MaybeEnableCompression( } #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB if (avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "zlib-deflate") { @@ -3737,7 +3740,7 @@ bool GDBRemoteCommunicationClient::ReadExtFeature( case ('m'): if (str.length() > 1) output << &str[1]; - offset += size; + offset += str.length() - 1; break; // unknown chunk diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 574cd0fd70c5..11fd40bce44f 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -89,7 +89,7 @@ public: /// Sends a GDB remote protocol 'A' packet that delivers program /// arguments to the remote server. /// - /// \param[in] argv + /// \param[in] launch_info /// A NULL terminated array of const C strings to use as the /// arguments. /// @@ -155,7 +155,7 @@ public: /// Sets the path to use for stdin/out/err for a process /// that will be launched with the 'A' packet. /// - /// \param[in] path + /// \param[in] file_spec /// The path to use for stdin/out/err /// /// \return @@ -596,6 +596,8 @@ protected: Status GetQXferMemoryMapRegionInfo(lldb::addr_t addr, MemoryRegionInfo ®ion); + LazyBool GetThreadPacketSupported(lldb::tid_t tid, llvm::StringRef packetStr); + private: DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationClient); }; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp index d2cc32f63f20..9e5646985f87 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp @@ -40,8 +40,8 @@ void GDBRemoteCommunicationHistory::AddPacket(char packet_char, m_packets[idx].bytes_transmitted = bytes_transmitted; m_packets[idx].packet_idx = m_total_packet_count; m_packets[idx].tid = llvm::get_threadid(); - if (m_stream) - m_packets[idx].Serialize(*m_stream); + if (m_recorder) + m_recorder->Record(m_packets[idx]); } void GDBRemoteCommunicationHistory::AddPacket(const std::string &src, @@ -58,8 +58,8 @@ void GDBRemoteCommunicationHistory::AddPacket(const std::string &src, m_packets[idx].bytes_transmitted = bytes_transmitted; m_packets[idx].packet_idx = m_total_packet_count; m_packets[idx].tid = llvm::get_threadid(); - if (m_stream) - m_packets[idx].Serialize(*m_stream); + if (m_recorder) + m_recorder->Record(m_packets[idx]); } void GDBRemoteCommunicationHistory::Dump(Stream &strm) const { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h index c006fbd34a4b..ee265ef86dff 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h @@ -13,11 +13,15 @@ #include <vector> #include "lldb/Utility/GDBRemote.h" +#include "lldb/Utility/Reproducer.h" #include "lldb/lldb-public.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" namespace lldb_private { +namespace repro { +class PacketRecorder; +} namespace process_gdb_remote { /// The history keeps a circular buffer of GDB remote packets. The history is @@ -41,7 +45,7 @@ public: void Dump(Log *log) const; bool DidDumpToLog() const { return m_dumped_to_log; } - void SetStream(llvm::raw_ostream *strm) { m_stream = strm; } + void SetRecorder(repro::PacketRecorder *recorder) { m_recorder = recorder; } private: uint32_t GetFirstSavedPacketIndex() const { @@ -73,7 +77,7 @@ private: uint32_t m_curr_idx; uint32_t m_total_packet_count; mutable bool m_dumped_to_log; - llvm::raw_ostream *m_stream = nullptr; + repro::PacketRecorder *m_recorder = nullptr; }; } // namespace process_gdb_remote diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp index 2d26c550dc76..15c73e78bd44 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp @@ -143,7 +143,14 @@ GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( entry.packet.data); LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'", packet.GetStringRef()); - assert(false && "Encountered unexpected packet during replay"); +#ifndef NDEBUG + // This behaves like a regular assert, but prints the expected and + // received packet before aborting. + printf("Reproducer expected packet: '%s'\n", entry.packet.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; } @@ -204,9 +211,9 @@ bool GDBRemoteCommunicationReplayServer::StartAsyncThread() { "<lldb.gdb-replay.async>", GDBRemoteCommunicationReplayServer::AsyncThread, this); if (!async_thread) { - LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), - "failed to launch host thread: {}", - llvm::toString(async_thread.takeError())); + LLDB_LOG_ERROR(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), + async_thread.takeError(), + "failed to launch host thread: {}"); return false; } m_async_thread = *async_thread; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 37980d914dc2..4b5fc0774a6d 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -429,7 +429,7 @@ GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qUserName( StringExtractorGDBRemote &packet) { -#if !defined(LLDB_DISABLE_POSIX) +#if LLDB_ENABLE_POSIX Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); LLDB_LOGF(log, "GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__); @@ -452,7 +452,7 @@ GDBRemoteCommunicationServerCommon::Handle_qUserName( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qGroupName( StringExtractorGDBRemote &packet) { -#if !defined(LLDB_DISABLE_POSIX) +#if LLDB_ENABLE_POSIX // Packet format: "qGroupName:%i" where %i is the gid packet.SetFilePos(::strlen("qGroupName:")); uint32_t gid = packet.GetU32(UINT32_MAX); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index ad1a39b57969..f33f0ee66304 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -669,9 +669,9 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( response.PutStringAsRawHex8(unescaped_response.GetData()); response.PutChar(';'); } else { - LLDB_LOG(log, "failed to prepare a jstopinfo field for pid {0}:", - m_debugged_process_up->GetID(), - llvm::toString(threads_info.takeError())); + LLDB_LOG_ERROR(log, threads_info.takeError(), + "failed to prepare a jstopinfo field for pid {1}: {0}", + m_debugged_process_up->GetID()); } } @@ -2013,7 +2013,7 @@ GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) { } const uint8_t *const data = - reinterpret_cast<const uint8_t *>(reg_value.GetBytes()); + static_cast<const uint8_t *>(reg_value.GetBytes()); if (!data) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed to get data " @@ -3087,9 +3087,9 @@ GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo( llvm::Expected<json::Value> threads_info = GetJSONThreadsInfo( *m_debugged_process_up, threads_with_valid_stop_info_only); if (!threads_info) { - LLDB_LOG(log, "failed to prepare a packet for pid {0}: {1}", - m_debugged_process_up->GetID(), - llvm::toString(threads_info.takeError())); + LLDB_LOG_ERROR(log, threads_info.takeError(), + "failed to prepare a packet for pid {1}: {0}", + m_debugged_process_up->GetID()); return SendErrorResponse(52); } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index c06c9527708e..ec1a54afd727 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -31,9 +31,11 @@ using namespace lldb_private::process_gdb_remote; // GDBRemoteRegisterContext constructor GDBRemoteRegisterContext::GDBRemoteRegisterContext( ThreadGDBRemote &thread, uint32_t concrete_frame_idx, - GDBRemoteDynamicRegisterInfo ®_info, bool read_all_at_once) + GDBRemoteDynamicRegisterInfo ®_info, bool read_all_at_once, + bool write_all_at_once) : RegisterContext(thread, concrete_frame_idx), m_reg_info(reg_info), - m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once) { + m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once), + m_write_all_at_once(write_all_at_once) { // Resize our vector of bools to contain one bool for every register. We will // use these boolean values to know when a register value is valid in // m_reg_data. @@ -87,6 +89,9 @@ bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { // Read the register if (ReadRegisterBytes(reg_info, m_reg_data)) { + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + if (m_reg_valid[reg] == false) + return false; const bool partial_data_ok = false; Status error(value.SetValueFromData( reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok)); @@ -203,6 +208,18 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, if (buffer_sp->GetByteSize() >= m_reg_data.GetByteSize()) { SetAllRegisterValid(true); return true; + } else if (buffer_sp->GetByteSize() > 0) { + const int regcount = m_reg_info.GetNumRegisters(); + for (int i = 0; i < regcount; i++) { + struct RegisterInfo *reginfo = m_reg_info.GetRegisterInfoAtIndex(i); + if (reginfo->byte_offset + reginfo->byte_size + <= buffer_sp->GetByteSize()) { + m_reg_valid[i] = true; + } else { + m_reg_valid[i] = false; + } + } + return true; } else { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); @@ -333,7 +350,7 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, { GDBRemoteClientBase::Lock lock(gdb_comm, false); if (lock) { - if (m_read_all_at_once) { + if (m_write_all_at_once) { // Invalidate all register values InvalidateIfNeeded(true); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 25e9b716f8cb..b42c87b5991b 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -41,7 +41,7 @@ class GDBRemoteRegisterContext : public RegisterContext { public: GDBRemoteRegisterContext(ThreadGDBRemote &thread, uint32_t concrete_frame_idx, GDBRemoteDynamicRegisterInfo ®_info, - bool read_all_at_once); + bool read_all_at_once, bool write_all_at_once); ~GDBRemoteRegisterContext() override; @@ -114,6 +114,7 @@ protected: std::vector<bool> m_reg_valid; DataExtractor m_reg_data; bool m_read_all_at_once; + bool m_write_all_at_once; private: // Helper function for ReadRegisterBytes(). diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index f1762abc55f8..a49db5d9a934 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -10,7 +10,7 @@ #include <errno.h> #include <stdlib.h> -#ifndef LLDB_DISABLE_POSIX +#if LLDB_ENABLE_POSIX #include <netinet/in.h> #include <sys/mman.h> #include <sys/socket.h> @@ -154,6 +154,11 @@ public: nullptr, idx, g_processgdbremote_properties[idx].default_uint_value != 0); } + + bool GetUseGPacketForReading() const { + const uint32_t idx = ePropertyUseGPacketForReading; + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); + } }; typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; @@ -274,12 +279,9 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, "async thread did exit"); if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { - repro::ProcessGDBRemoteProvider &provider = - g->GetOrCreate<repro::ProcessGDBRemoteProvider>(); - // Set the history stream to the stream owned by the provider. - m_gdb_comm.SetHistoryStream(provider.GetHistoryStream()); - // Make sure to clear the stream again when we're finished. - provider.SetCallback([&]() { m_gdb_comm.SetHistoryStream(nullptr); }); + repro::GDBRemoteProvider &provider = + g->GetOrCreate<repro::GDBRemoteProvider>(); + m_gdb_comm.SetPacketRecorder(provider.GetNewPacketRecorder()); } Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_ASYNC)); @@ -309,6 +311,9 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, GetGlobalPluginProperties()->GetPacketTimeout(); if (timeout_seconds > 0) m_gdb_comm.SetPacketTimeout(std::chrono::seconds(timeout_seconds)); + + m_use_g_packet_for_reading = + GetGlobalPluginProperties()->GetUseGPacketForReading(); } // Destructor @@ -380,36 +385,6 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition( return false; } -// If the remote stub didn't give us eh_frame or DWARF register numbers for a -// register, see if the ABI can provide them. -// DWARF and eh_frame register numbers are defined as a part of the ABI. -static void AugmentRegisterInfoViaABI(RegisterInfo ®_info, - ConstString reg_name, ABISP abi_sp) { - if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM || - reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM) { - if (abi_sp) { - RegisterInfo abi_reg_info; - if (abi_sp->GetRegisterInfoByName(reg_name, abi_reg_info)) { - if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) { - reg_info.kinds[eRegisterKindEHFrame] = - abi_reg_info.kinds[eRegisterKindEHFrame]; - } - if (reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM) { - reg_info.kinds[eRegisterKindDWARF] = - abi_reg_info.kinds[eRegisterKindDWARF]; - } - if (reg_info.kinds[eRegisterKindGeneric] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) { - reg_info.kinds[eRegisterKindGeneric] = - abi_reg_info.kinds[eRegisterKindGeneric]; - } - } - } - } -} - static size_t SplitCommaSeparatedRegisterNumberString( const llvm::StringRef &comma_separated_regiter_numbers, std::vector<uint32_t> ®nums, int base) { @@ -607,12 +582,12 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { reg_info.invalidate_regs = invalidate_regs.data(); } + reg_info.name = reg_name.AsCString(); // We have to make a temporary ABI here, and not use the GetABI because // this code gets called in DidAttach, when the target architecture // (and consequently the ABI we'll get from the process) may be wrong. - ABISP abi_to_use = ABI::FindPlugin(shared_from_this(), arch_to_use); - - AugmentRegisterInfoViaABI(reg_info, reg_name, abi_to_use); + if (ABISP abi_sp = ABI::FindPlugin(shared_from_this(), arch_to_use)) + abi_sp->AugmentRegisterInfo(reg_info); m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); } else { @@ -2374,21 +2349,22 @@ void ProcessGDBRemote::RefreshStateAfterStop() { m_thread_ids.clear(); m_thread_pcs.clear(); + // Set the thread stop info. It might have a "threads" key whose value is a // list of all thread IDs in the current process, so m_thread_ids might get // set. + // Check to see if SetThreadStopInfo() filled in m_thread_ids? + if (m_thread_ids.empty()) { + // No, we need to fetch the thread list manually + UpdateThreadIDList(); + } + + // We might set some stop info's so make sure the thread list is up to + // date before we do that or we might overwrite what was computed here. + UpdateThreadListIfNeeded(); // Scope for the lock { - // Check to see if SetThreadStopInfo() filled in m_thread_ids? - if (m_thread_ids.empty()) { - // No, we need to fetch the thread list manually - UpdateThreadIDList(); - } - // We might set some stop info's so make sure the thread list is up to - // date before we do that or we might overwrite what was computed here. - UpdateThreadListIfNeeded(); - // Lock the thread stack while we access it std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex); // Get the number of stop packets on the stack @@ -3384,17 +3360,20 @@ Status ProcessGDBRemote::ConnectToReplayServer(repro::Loader *loader) { if (!loader) return Status("No loader provided."); - // Construct replay history path. - FileSpec history_file = - loader->GetFile<repro::ProcessGDBRemoteProvider::Info>(); - if (!history_file) - return Status("No provider for gdb-remote."); + static std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>> + multi_loader = repro::MultiLoader<repro::GDBRemoteProvider>::Create( + repro::Reproducer::Instance().GetLoader()); - // Enable replay mode. - m_replay_mode = true; + 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."); // Load replay history. - if (auto error = m_gdb_replay_server.LoadReplayHistory(history_file)) + if (auto error = + m_gdb_replay_server.LoadReplayHistory(FileSpec(*history_file))) return Status("Unable to load replay history"); // Make a local connection. @@ -3402,6 +3381,9 @@ Status ProcessGDBRemote::ConnectToReplayServer(repro::Loader *loader) { m_gdb_replay_server)) return Status("Unable to connect to replay server"); + // Enable replay mode. + m_replay_mode = true; + // Start server thread. m_gdb_replay_server.StartAsyncThread(); @@ -3627,9 +3609,9 @@ bool ProcessGDBRemote::StartAsyncThread() { llvm::Expected<HostThread> async_thread = ThreadLauncher::LaunchThread( "<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this); if (!async_thread) { - LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), - "failed to launch host thread: {}", - llvm::toString(async_thread.takeError())); + LLDB_LOG_ERROR(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), + async_thread.takeError(), + "failed to launch host thread: {}"); return false; } m_async_thread = *async_thread; @@ -4475,7 +4457,9 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, } ++cur_reg_num; - AugmentRegisterInfoViaABI(reg_info, reg_name, abi_sp); + reg_info.name = reg_name.AsCString(); + if (abi_sp) + abi_sp->AugmentRegisterInfo(reg_info); dyn_reg_info.AddRegister(reg_info, reg_name, alt_name, set_name); return true; // Keep iterating through all "reg" elements diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 0e3e3b39d9c8..9ea3940103b6 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -284,6 +284,7 @@ protected: lldb::CommandObjectSP m_command_sp; int64_t m_breakpoint_pc_offset; 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; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td index 16e7723e3061..9cbe3d40ca2c 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td @@ -13,4 +13,8 @@ let Definition = "processgdbremote" in { Global, DefaultFalse, Desc<"If true, the libraries-svr4 feature will be used to get a hold of the process's loaded modules.">; + def UseGPacketForReading: Property<"use-g-packet-for-reading", "Boolean">, + Global, + DefaultFalse, + Desc<"Specify if the server should use 'g' packets to read registers.">; } diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 8a6a58c55450..9da481979f73 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -301,13 +301,14 @@ ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) { if (process_sp) { ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); - // read_all_registers_at_once will be true if 'p' packet is not - // supported. + bool pSupported = + gdb_process->GetGDBRemote().GetpPacketSupported(GetID()); bool read_all_registers_at_once = - !gdb_process->GetGDBRemote().GetpPacketSupported(GetID()); + !pSupported || gdb_process->m_use_g_packet_for_reading; + bool write_all_registers_at_once = !pSupported; reg_ctx_sp = std::make_shared<GDBRemoteRegisterContext>( *this, concrete_frame_idx, gdb_process->m_register_info, - read_all_registers_at_once); + read_all_registers_at_once, write_all_registers_at_once); } } else { Unwind *unwinder = GetUnwinder(); diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp index 70933f91fe51..3c0e1cb49d1d 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -174,6 +174,7 @@ ArchSpec MinidumpParser::GetArchitecture() { triple.setArch(llvm::Triple::ArchType::arm); break; case ProcessorArchitecture::ARM64: + case ProcessorArchitecture::BP_ARM64: triple.setArch(llvm::Triple::ArchType::aarch64); break; default: @@ -518,58 +519,26 @@ CreateRegionsCacheFromMemory64List(MinidumpParser &parser, return !regions.empty(); } -MemoryRegionInfo -MinidumpParser::FindMemoryRegion(lldb::addr_t load_addr) const { - auto begin = m_regions.begin(); - auto end = m_regions.end(); - auto pos = std::lower_bound(begin, end, load_addr); - if (pos != end && pos->GetRange().Contains(load_addr)) - return *pos; - - MemoryRegionInfo region; - if (pos == begin) - region.GetRange().SetRangeBase(0); - else { - auto prev = pos - 1; - if (prev->GetRange().Contains(load_addr)) - return *prev; - region.GetRange().SetRangeBase(prev->GetRange().GetRangeEnd()); - } - if (pos == end) - region.GetRange().SetRangeEnd(UINT64_MAX); - else - region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase()); - region.SetReadable(MemoryRegionInfo::eNo); - region.SetWritable(MemoryRegionInfo::eNo); - region.SetExecutable(MemoryRegionInfo::eNo); - region.SetMapped(MemoryRegionInfo::eNo); - return region; -} - -MemoryRegionInfo -MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) { - if (!m_parsed_regions) - GetMemoryRegions(); - return FindMemoryRegion(load_addr); -} - -const MemoryRegionInfos &MinidumpParser::GetMemoryRegions() { - if (!m_parsed_regions) { - m_parsed_regions = true; - // We haven't cached our memory regions yet we will create the region cache - // once. We create the region cache using the best source. We start with - // the linux maps since they are the most complete and have names for the - // regions. Next we try the MemoryInfoList since it has - // read/write/execute/map data, and then fall back to the MemoryList and - // Memory64List to just get a list of the memory that is mapped in this - // core file - if (!CreateRegionsCacheFromLinuxMaps(*this, m_regions)) - if (!CreateRegionsCacheFromMemoryInfoList(*this, m_regions)) - if (!CreateRegionsCacheFromMemoryList(*this, m_regions)) - CreateRegionsCacheFromMemory64List(*this, m_regions); - llvm::sort(m_regions.begin(), m_regions.end()); - } - return m_regions; +std::pair<MemoryRegionInfos, bool> MinidumpParser::BuildMemoryRegions() { + // We create the region cache using the best source. We start with + // the linux maps since they are the most complete and have names for the + // regions. Next we try the MemoryInfoList since it has + // read/write/execute/map data, and then fall back to the MemoryList and + // Memory64List to just get a list of the memory that is mapped in this + // core file + MemoryRegionInfos result; + const auto &return_sorted = [&](bool is_complete) { + llvm::sort(result); + return std::make_pair(std::move(result), is_complete); + }; + if (CreateRegionsCacheFromLinuxMaps(*this, result)) + return return_sorted(true); + if (CreateRegionsCacheFromMemoryInfoList(*this, result)) + return return_sorted(true); + if (CreateRegionsCacheFromMemoryList(*this, result)) + return return_sorted(false); + CreateRegionsCacheFromMemory64List(*this, result); + return return_sorted(false); } #define ENUM_TO_CSTR(ST) \ diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/lldb/source/Plugins/Process/minidump/MinidumpParser.h index d206fe6c9a00..4bcb2b47d45a 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.h +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.h @@ -88,9 +88,9 @@ public: llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size); - MemoryRegionInfo GetMemoryRegionInfo(lldb::addr_t load_addr); - - const MemoryRegionInfos &GetMemoryRegions(); + /// Returns a list of memory regions and a flag indicating whether the list is + /// complete (includes all regions mapped into the process memory). + std::pair<MemoryRegionInfos, bool> BuildMemoryRegions(); static llvm::StringRef GetStreamTypeAsString(StreamType stream_type); @@ -100,14 +100,10 @@ private: MinidumpParser(lldb::DataBufferSP data_sp, std::unique_ptr<llvm::object::MinidumpFile> file); - MemoryRegionInfo FindMemoryRegion(lldb::addr_t load_addr) const; - private: lldb::DataBufferSP m_data_sp; std::unique_ptr<llvm::object::MinidumpFile> m_file; ArchSpec m_arch; - MemoryRegionInfos m_regions; - bool m_parsed_regions = false; }; } // end namespace minidump diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index e30a3c82a887..5c090dc6e12f 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -334,15 +334,84 @@ ArchSpec ProcessMinidump::GetArchitecture() { return ArchSpec(triple); } +static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos ®ions, + lldb::addr_t load_addr) { + MemoryRegionInfo region; + auto pos = llvm::upper_bound(regions, load_addr); + if (pos != regions.begin() && + std::prev(pos)->GetRange().Contains(load_addr)) { + return *std::prev(pos); + } + + if (pos == regions.begin()) + region.GetRange().SetRangeBase(0); + else + region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd()); + + if (pos == regions.end()) + region.GetRange().SetRangeEnd(UINT64_MAX); + else + region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase()); + + region.SetReadable(MemoryRegionInfo::eNo); + region.SetWritable(MemoryRegionInfo::eNo); + region.SetExecutable(MemoryRegionInfo::eNo); + region.SetMapped(MemoryRegionInfo::eNo); + return region; +} + +void ProcessMinidump::BuildMemoryRegions() { + if (m_memory_regions) + return; + m_memory_regions.emplace(); + bool is_complete; + std::tie(*m_memory_regions, is_complete) = + m_minidump_parser->BuildMemoryRegions(); + + if (is_complete) + return; + + MemoryRegionInfos to_add; + ModuleList &modules = GetTarget().GetImages(); + SectionLoadList &load_list = GetTarget().GetSectionLoadList(); + modules.ForEach([&](const ModuleSP &module_sp) { + SectionList *sections = module_sp->GetSectionList(); + for (size_t i = 0; i < sections->GetSize(); ++i) { + SectionSP section_sp = sections->GetSectionAtIndex(i); + addr_t load_addr = load_list.GetSectionLoadAddress(section_sp); + if (load_addr == LLDB_INVALID_ADDRESS) + continue; + MemoryRegionInfo::RangeType section_range(load_addr, + section_sp->GetByteSize()); + MemoryRegionInfo region = + ::GetMemoryRegionInfo(*m_memory_regions, load_addr); + if (region.GetMapped() != MemoryRegionInfo::eYes && + region.GetRange().GetRangeBase() <= section_range.GetRangeBase() && + section_range.GetRangeEnd() <= region.GetRange().GetRangeEnd()) { + to_add.emplace_back(); + to_add.back().GetRange() = section_range; + to_add.back().SetLLDBPermissions(section_sp->GetPermissions()); + to_add.back().SetMapped(MemoryRegionInfo::eYes); + to_add.back().SetName(module_sp->GetFileSpec().GetPath().c_str()); + } + } + return true; + }); + m_memory_regions->insert(m_memory_regions->end(), to_add.begin(), + to_add.end()); + llvm::sort(*m_memory_regions); +} + Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo &range_info) { - range_info = m_minidump_parser->GetMemoryRegionInfo(load_addr); + MemoryRegionInfo ®ion) { + BuildMemoryRegions(); + region = ::GetMemoryRegionInfo(*m_memory_regions, load_addr); return Status(); } -Status ProcessMinidump::GetMemoryRegions( - lldb_private::MemoryRegionInfos ®ion_list) { - region_list = m_minidump_parser->GetMemoryRegions(); +Status ProcessMinidump::GetMemoryRegions(MemoryRegionInfos ®ion_list) { + BuildMemoryRegions(); + region_list = *m_memory_regions; return Status(); } diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h index 22dc24af7c0e..750164cf8aaf 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h @@ -111,6 +111,9 @@ private: const minidump::ExceptionStream *m_active_exception; lldb::CommandObjectSP m_command_sp; bool m_is_wow64; + llvm::Optional<MemoryRegionInfos> m_memory_regions; + + void BuildMemoryRegions(); }; } // namespace minidump |