diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Plugins/Process')
91 files changed, 8197 insertions, 788 deletions
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index d13b9a4..4b48844 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -22,12 +22,23 @@ #include "ProcessFreeBSD.h" #include "ProcessPOSIXLog.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" +#include "Plugins/Process/Utility/FreeBSDSignals.h" #include "ProcessMonitor.h" #include "FreeBSDThread.h" using namespace lldb; using namespace lldb_private; +namespace +{ + UnixSignalsSP& + GetFreeBSDSignals () + { + static UnixSignalsSP s_freebsd_signals_sp (new FreeBSDSignals ()); + return s_freebsd_signals_sp; + } +} + //------------------------------------------------------------------------------ // Static functions. @@ -113,7 +124,8 @@ ProcessFreeBSD::EnablePluginLogging(Stream *strm, Args &command) // Constructors and destructors. ProcessFreeBSD::ProcessFreeBSD(Target& target, Listener &listener) - : ProcessPOSIX(target, listener) + : ProcessPOSIX(target, listener, GetFreeBSDSignals ()), + m_resume_signo(0) { } @@ -132,8 +144,6 @@ ProcessFreeBSD::DoDetach(bool keep_stopped) return error; } - DisableAllBreakpointSites(); - error = m_monitor->Detach(GetID()); if (error.Success()) @@ -147,9 +157,6 @@ ProcessFreeBSD::DoResume() { Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - // FreeBSD's ptrace() uses 0 to indicate "no signal is to be sent." - int resume_signal = 0; - SetPrivateState(eStateRunning); Mutex::Locker lock(m_thread_list.GetMutex()); @@ -172,11 +179,11 @@ ProcessFreeBSD::DoResume() } if (log) - log->Printf("process %lu resuming (%s)", GetID(), do_step ? "step" : "continue"); + log->Printf("process %" PRIu64 " resuming (%s)", GetID(), do_step ? "step" : "continue"); if (do_step) - m_monitor->SingleStep(GetID(), resume_signal); + m_monitor->SingleStep(GetID(), m_resume_signo); else - m_monitor->Resume(GetID(), resume_signal); + m_monitor->Resume(GetID(), m_resume_signo); return Error(); } @@ -228,6 +235,7 @@ ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_th Error ProcessFreeBSD::WillResume() { + m_resume_signo = 0; m_suspend_tids.clear(); m_run_tids.clear(); m_step_tids.clear(); @@ -274,4 +282,3 @@ ProcessFreeBSD::SendMessage(const ProcessMessage &message) m_message_queue.push(message); } - diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 3d793d0..63439b1 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -702,7 +702,7 @@ EventMessageOperation::Execute(ProcessMonitor *monitor) //------------------------------------------------------------------------------ /// @class KillOperation -/// @brief Implements ProcessMonitor::BringProcessIntoLimbo. +/// @brief Implements ProcessMonitor::Kill. class KillOperation : public Operation { public: @@ -727,7 +727,7 @@ KillOperation::Execute(ProcessMonitor *monitor) //------------------------------------------------------------------------------ /// @class DetachOperation -/// @brief Implements ProcessMonitor::BringProcessIntoLimbo. +/// @brief Implements ProcessMonitor::Detach. class DetachOperation : public Operation { public: @@ -807,6 +807,7 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process, const char *stdout_path, const char *stderr_path, const char *working_dir, + const lldb_private::ProcessLaunchInfo & /* launch_info */, lldb_private::Error &error) : m_process(static_cast<ProcessFreeBSD *>(process)), m_operation_thread(LLDB_INVALID_HOST_THREAD), @@ -1628,9 +1629,13 @@ ProcessMonitor::Resume(lldb::tid_t unused, uint32_t signo) bool result; Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - if (log) - log->Printf ("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s", __FUNCTION__, GetPID(), - m_process->GetUnixSignals().GetSignalAsCString (signo)); + if (log) { + const char *signame = m_process->GetUnixSignals().GetSignalAsCString (signo); + if (signame == nullptr) + signame = "<none>"; + log->Printf("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s", + __FUNCTION__, GetPID(), signame); + } ResumeOperation op(signo, result); DoOperation(&op); if (log) @@ -1648,7 +1653,7 @@ ProcessMonitor::SingleStep(lldb::tid_t unused, uint32_t signo) } bool -ProcessMonitor::BringProcessIntoLimbo() +ProcessMonitor::Kill() { bool result; KillOperation op(result); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 4c8198f..314743b 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -55,6 +55,7 @@ public: const char *stdout_path, const char *stderr_path, const char *working_dir, + const lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Error &error); ProcessMonitor(ProcessPOSIX *process, @@ -194,11 +195,9 @@ public: bool SingleStep(lldb::tid_t unused, uint32_t signo); - /// Sends the inferior process a PTRACE_KILL signal. The inferior will - /// still exists and can be interrogated. Once resumed it will exit as - /// though it received a SIGKILL. + /// Terminate the traced process. bool - BringProcessIntoLimbo(); + Kill(); lldb_private::Error Detach(lldb::tid_t tid); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp index cc759ea..d48f8f9 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp @@ -20,6 +20,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/State.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Target/Process.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" @@ -29,8 +30,10 @@ #include "ProcessPOSIX.h" #include "ProcessPOSIXLog.h" #include "ProcessMonitor.h" +#include "RegisterContextPOSIXProcessMonitor_arm64.h" #include "RegisterContextPOSIXProcessMonitor_mips64.h" #include "RegisterContextPOSIXProcessMonitor_x86.h" +#include "RegisterContextLinux_arm64.h" #include "RegisterContextLinux_i386.h" #include "RegisterContextLinux_x86_64.h" #include "RegisterContextFreeBSD_i386.h" @@ -110,7 +113,7 @@ POSIXThread::RefreshStateAfterStop() GetRegisterContext()->InvalidateIfNeeded (force); } // FIXME: This should probably happen somewhere else. - SetResumeState(eStateRunning); + SetResumeState(eStateRunning, true); Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); if (log) log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to running", __FUNCTION__, GetID()); @@ -156,58 +159,82 @@ POSIXThread::GetRegisterContext() RegisterInfoInterface *reg_interface = NULL; const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture(); - switch (target_arch.GetCore()) + switch (target_arch.GetTriple().getOS()) { - case ArchSpec::eCore_mips64: - { - switch (target_arch.GetTriple().getOS()) + case llvm::Triple::FreeBSD: + switch (target_arch.GetMachine()) { - case llvm::Triple::FreeBSD: + case llvm::Triple::mips64: reg_interface = new RegisterContextFreeBSD_mips64(target_arch); break; + case llvm::Triple::x86: + reg_interface = new RegisterContextFreeBSD_i386(target_arch); + break; + case llvm::Triple::x86_64: + reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); + break; default: - assert(false && "OS not supported"); break; } - - if (reg_interface) - { - RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - } break; - } - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - case ArchSpec::eCore_x86_64_x86_64: - { - switch (target_arch.GetTriple().getOS()) + case llvm::Triple::Linux: + switch (target_arch.GetMachine()) { - case llvm::Triple::FreeBSD: - reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); + case llvm::Triple::aarch64: + assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); + reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm64(target_arch)); break; - case llvm::Triple::Linux: - reg_interface = new RegisterContextLinux_x86_64(target_arch); + case llvm::Triple::x86: + case llvm::Triple::x86_64: + if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) + { + // 32-bit hosts run with a RegisterContextLinux_i386 context. + reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_i386(target_arch)); + } + else + { + assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && + "Register setting path assumes this is a 64-bit host"); + // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context. + reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_x86_64(target_arch)); + } break; default: - assert(false && "OS not supported"); break; } - if (reg_interface) + default: + break; + } + + assert(reg_interface && "OS or CPU not supported!"); + + switch (target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + { + RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm64(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + case llvm::Triple::mips64: + { + RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + case llvm::Triple::x86: + case llvm::Triple::x86_64: { RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, reg_interface); m_posix_thread = reg_ctx; m_reg_context_sp.reset(reg_ctx); + break; } - break; - } - default: - assert(false && "CPU type not supported!"); break; } } @@ -546,18 +573,14 @@ void POSIXThread::SignalNotify(const ProcessMessage &message) { int signo = message.GetSignal(); - SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo)); - SetResumeSignal(signo); } void POSIXThread::SignalDeliveredNotify(const ProcessMessage &message) { int signo = message.GetSignal(); - SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo)); - SetResumeSignal(signo); } void @@ -576,7 +599,6 @@ POSIXThread::CrashNotify(const ProcessMessage &message) SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo, message.GetCrashReason(), message.GetFaultAddress()))); - SetResumeSignal(signo); } void @@ -589,19 +611,18 @@ unsigned POSIXThread::GetRegisterIndexFromOffset(unsigned offset) { unsigned reg = LLDB_INVALID_REGNUM; - ArchSpec arch = Host::GetArchitecture(); + ArchSpec arch = HostInfo::GetArchitecture(); - switch (arch.GetCore()) + switch (arch.GetMachine()) { default: llvm_unreachable("CPU type not supported!"); break; - case ArchSpec::eCore_mips64: - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - case ArchSpec::eCore_x86_64_x86_64: + case llvm::Triple::aarch64: + case llvm::Triple::mips64: + case llvm::Triple::x86: + case llvm::Triple::x86_64: { POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); reg = reg_ctx->GetRegisterIndexFromOffset(offset); @@ -621,19 +642,18 @@ const char * POSIXThread::GetRegisterName(unsigned reg) { const char * name = nullptr; - ArchSpec arch = Host::GetArchitecture(); + ArchSpec arch = HostInfo::GetArchitecture(); - switch (arch.GetCore()) + switch (arch.GetMachine()) { default: assert(false && "CPU type not supported!"); break; - case ArchSpec::eCore_mips64: - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - case ArchSpec::eCore_x86_64_x86_64: + case llvm::Triple::aarch64: + case llvm::Triple::mips64: + case llvm::Triple::x86: + case llvm::Triple::x86_64: name = GetRegisterContext()->GetRegisterName(reg); break; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp index 1a8bf89..f340631 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -70,8 +70,8 @@ ProcessPOSIX::Initialize() //------------------------------------------------------------------------------ // Constructors and destructors. -ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener) - : Process(target, listener), +ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener, UnixSignalsSP &unix_signals_sp) + : Process(target, listener, unix_signals_sp), m_byte_order(lldb::endian::InlHostByteOrder()), m_monitor(NULL), m_module(NULL), @@ -176,23 +176,23 @@ ProcessPOSIX::WillLaunch(Module* module) } const char * -ProcessPOSIX::GetFilePath( - const lldb_private::ProcessLaunchInfo::FileAction *file_action, - const char *default_path) +ProcessPOSIX::GetFilePath(const lldb_private::FileAction *file_action, const char *default_path) { const char *pts_name = "/dev/pts/"; const char *path = NULL; if (file_action) { - if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen) + if (file_action->GetAction() == FileAction::eFileActionOpen) + { path = file_action->GetPath(); // By default the stdio paths passed in will be pseudo-terminal // (/dev/pts). If so, convert to using a different default path // instead to redirect I/O to the debugger console. This should // also handle user overrides to /dev/null or a different file. - if (::strncmp(path, pts_name, ::strlen(pts_name)) == 0) + if (!path || ::strncmp(path, pts_name, ::strlen(pts_name)) == 0) path = default_path; + } } return path; @@ -217,7 +217,7 @@ ProcessPOSIX::DoLaunch (Module *module, SetPrivateState(eStateLaunching); - const lldb_private::ProcessLaunchInfo::FileAction *file_action; + const lldb_private::FileAction *file_action; // Default of NULL will mean to use existing open file descriptors const char *stdin_path = NULL; @@ -241,6 +241,7 @@ ProcessPOSIX::DoLaunch (Module *module, stdout_path, stderr_path, working_dir, + launch_info, error); m_module = module; @@ -335,9 +336,9 @@ ProcessPOSIX::DoDestroy() if (!HasExited()) { - assert (m_monitor); + assert(m_monitor); m_exit_now = true; - if (m_monitor->BringProcessIntoLimbo()) + if (!m_monitor->Kill()) { error.SetErrorToErrno(); return error; @@ -377,6 +378,8 @@ ProcessPOSIX::DoDidExec() void ProcessPOSIX::SendMessage(const ProcessMessage &message) { + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + Mutex::Locker lock(m_message_mutex); Mutex::Locker thread_lock(m_thread_list.GetMutex()); @@ -418,8 +421,14 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) break; case ProcessMessage::eExitMessage: - assert(thread); - thread->SetState(eStateExited); + if (thread != nullptr) + thread->SetState(eStateExited); + else + { + if (log) + log->Warning ("ProcessPOSIX::%s eExitMessage for TID %" PRIu64 " failed to find a thread to mark as eStateExited, ignoring", __FUNCTION__, message.GetTID ()); + } + // FIXME: I'm not sure we need to do this. if (message.GetTID() == GetID()) { @@ -633,20 +642,26 @@ ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr) size_t ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) { + static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xD4 }; static const uint8_t g_i386_opcode[] = { 0xCC }; ArchSpec arch = GetTarget().GetArchitecture(); const uint8_t *opcode = NULL; size_t opcode_size = 0; - switch (arch.GetCore()) + switch (arch.GetMachine()) { default: assert(false && "CPU type not supported!"); break; - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_64_x86_64: + case llvm::Triple::aarch64: + opcode = g_aarch64_opcode; + opcode_size = sizeof(g_aarch64_opcode); + break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: opcode = g_i386_opcode; opcode_size = sizeof(g_i386_opcode); break; @@ -863,12 +878,6 @@ ProcessPOSIX::PutSTDIN(const char *buf, size_t len, Error &error) return status; } -UnixSignals & -ProcessPOSIX::GetUnixSignals() -{ - return m_signals; -} - //------------------------------------------------------------------------------ // Utility functions. @@ -924,3 +933,16 @@ ProcessPOSIX::IsAThreadRunning() } return is_running; } + +const DataBufferSP +ProcessPOSIX::GetAuxvData () +{ + // If we're the local platform, we can ask the host for auxv data. + PlatformSP platform_sp = m_target.GetPlatform (); + if (platform_sp && platform_sp->IsHost ()) + return lldb_private::Host::GetAuxvData(this); + + // Somewhat unexpected - the process is not running locally or we don't have a platform. + assert (false && "no platform or not the host - how did we get here with ProcessPOSIX?"); + return DataBufferSP (); +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h index 7f705d3..033accf 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h @@ -18,7 +18,6 @@ // Other libraries and framework includes #include "lldb/Target/Process.h" -#include "lldb/Target/UnixSignals.h" #include "ProcessMessage.h" class ProcessMonitor; @@ -33,7 +32,8 @@ public: // Constructors and destructors //------------------------------------------------------------------ ProcessPOSIX(lldb_private::Target& target, - lldb_private::Listener &listener); + lldb_private::Listener &listener, + lldb_private::UnixSignalsSP &unix_signals_sp); virtual ~ProcessPOSIX(); @@ -141,6 +141,9 @@ public: virtual size_t PutSTDIN(const char *buf, size_t len, lldb_private::Error &error); + const lldb::DataBufferSP + GetAuxvData () override; + //-------------------------------------------------------------------------- // ProcessPOSIX internal API. @@ -151,12 +154,7 @@ public: ProcessMonitor & GetMonitor() { assert(m_monitor); return *m_monitor; } - lldb_private::UnixSignals & - GetUnixSignals(); - - const char * - GetFilePath(const lldb_private::ProcessLaunchInfo::FileAction *file_action, - const char *default_path); + const char *GetFilePath(const lldb_private::FileAction *file_action, const char *default_path); /// Stops all threads in the process. /// The \p stop_tid parameter indicates the thread which initiated the stop. @@ -164,7 +162,7 @@ public: StopAllThreads(lldb::tid_t stop_tid); /// Adds the thread to the list of threads for which we have received the initial stopping signal. - /// The \p stop_tid paramter indicates the thread which the stop happened for. + /// The \p stop_tid parameter indicates the thread which the stop happened for. bool AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid); @@ -191,9 +189,6 @@ protected: /// Drive any exit events to completion. bool m_exit_now; - /// OS-specific signal set. - lldb_private::UnixSignals m_signals; - /// Returns true if the process has exited. bool HasExited(); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp new file mode 100644 index 0000000..9109cdb --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp @@ -0,0 +1,318 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm64.cpp -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "lldb/Target/Thread.h" +#include "lldb/Core/RegisterValue.h" + +#include "RegisterContextPOSIX_arm64.h" +#include "ProcessPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_arm64.h" +#include "ProcessMonitor.h" + +#define REG_CONTEXT_SIZE (GetGPRSize()) + +RegisterContextPOSIXProcessMonitor_arm64::RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_arm64(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_arm64::GetMonitor() +{ + lldb::ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const unsigned reg, + lldb_private::RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const unsigned reg, + const lldb_private::RegisterValue &value) +{ + unsigned reg_to_write = reg; + lldb_private::RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + lldb_private::RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const lldb_private::RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + lldb_private::Error error; + lldb::ByteOrder byte_order = GetByteOrder(); + uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[lldb_private::RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + ::memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + } + + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsFPR(reg)) + { + if (!ReadFPR()) + return false; + } + else + { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); + + if (is_subreg) + { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; + } + return ReadRegister(full_reg, value); + } + + // Get pointer to m_fpr variable and set the data from it. + assert (reg_info->byte_offset < sizeof m_fpr); + uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 2: + value.SetUInt16(*(uint16_t *)src); + return true; + case 4: + value.SetUInt32(*(uint32_t *)src); + return true; + case 8: + value.SetUInt64(*(uint64_t *)src); + return true; + default: + assert(false && "Unhandled data size."); + return false; + } +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsGPR(reg)) + return WriteRegister(reg, value); + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new lldb_private::DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR () && ReadFPR ()) + { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) + { + ::memcpy (dst, &m_gpr_arm64, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy (dst, &m_fpr, sizeof m_fpr); + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + uint8_t *src = data_sp->GetBytes(); + if (src) + { + ::memcpy (&m_gpr_arm64, src, GetGPRSize()); + if (WriteGPR()) { + src += GetGPRSize(); + ::memcpy (&m_fpr, src, sizeof m_fpr); + success = WriteFPR(); + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, + read, write, + hw_index); + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint() +{ + // PC points one byte past the int3 responsible for the breakpoint. + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + SetPC(pc - 1); + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < k_num_registers_arm64; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_arm64 && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits() +{ + return false; +} + +lldb::addr_t +RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress(uint32_t hw_index) +{ + return LLDB_INVALID_ADDRESS; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints() +{ + return 0; +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h new file mode 100644 index 0000000..eb24d48 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm64.h --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" + +class RegisterContextPOSIXProcessMonitor_arm64: + public RegisterContextPOSIX_arm64, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + + // lldb_private::RegisterContext + bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + + bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + + bool + HardwareSingleStep(bool enable); + + // POSIXBreakpointProtocol + bool + UpdateAfterBreakpoint(); + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + bool + IsWatchpointHit(uint32_t hw_index); + + bool + ClearWatchpointHits(); + + lldb::addr_t + GetWatchpointAddress(uint32_t hw_index); + + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + + uint32_t + NumSupportedHardwareWatchpoints(); + +private: + ProcessMonitor & + GetMonitor(); +}; + +#endif diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp index f70d00e..9bfe236 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp @@ -22,7 +22,7 @@ using namespace lldb; RegisterContextPOSIXProcessMonitor_mips64::RegisterContextPOSIXProcessMonitor_mips64(Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info) + lldb_private::RegisterInfoInterface *register_info) : RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info) { } @@ -196,7 +196,6 @@ RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues(DataBufferSP &d if (success) { ::memcpy (dst, &m_gpr_mips64, GetGPRSize()); - dst += GetGPRSize(); } } return success; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h index 8f545ee..79e4468 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h @@ -10,7 +10,7 @@ #ifndef liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ #define liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ -#include "Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" class RegisterContextPOSIXProcessMonitor_mips64: public RegisterContextPOSIX_mips64, @@ -19,7 +19,7 @@ class RegisterContextPOSIXProcessMonitor_mips64: public: RegisterContextPOSIXProcessMonitor_mips64(lldb_private::Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info); + lldb_private::RegisterInfoInterface *register_info); protected: bool diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp index c446bbf..e534f3b 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -53,7 +53,7 @@ size_and_rw_bits(size_t size, bool read, bool write) RegisterContextPOSIXProcessMonitor_x86_64::RegisterContextPOSIXProcessMonitor_x86_64(Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info) + lldb_private::RegisterInfoInterface *register_info) : RegisterContextPOSIX_x86(thread, concrete_frame_idx, register_info) { } @@ -347,12 +347,12 @@ RegisterContextPOSIXProcessMonitor_x86_64::ReadAllRegisterValues(DataBufferSP &d if (success) { - ::memcpy (dst, &m_gpr_x86_64, GetGPRSize()); - dst += GetGPRSize(); + ::memcpy (dst, &m_gpr_x86_64, GetGPRSize()); + dst += GetGPRSize(); + if (GetFPRType() == eFXSAVE) + ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); } - if (GetFPRType() == eFXSAVE) - ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); - + if (GetFPRType() == eXSAVE) { ByteOrder byte_order = GetByteOrder(); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h index 2b64fa8..2afb195 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h @@ -10,7 +10,7 @@ #ifndef liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ #define liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ -#include "Plugins/Process/POSIX/RegisterContextPOSIX_x86.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h" class RegisterContextPOSIXProcessMonitor_x86_64: public RegisterContextPOSIX_x86, @@ -19,7 +19,7 @@ class RegisterContextPOSIXProcessMonitor_x86_64: public: RegisterContextPOSIXProcessMonitor_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info); + lldb_private::RegisterInfoInterface *register_info); protected: bool diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMDefines.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMDefines.h index 4b1f06a..2c8ad35 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMDefines.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMDefines.h @@ -10,7 +10,7 @@ #ifndef lldb_ARMDefines_h_ #define lldb_ARMDefines_h_ -// Common defintions for the ARM/Thumb Instruction Set Architecture. +// Common definitions for the ARM/Thumb Instruction Set Architecture. namespace lldb_private { diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMUtils.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMUtils.h index 76d64e1..b6ba3fe 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMUtils.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMUtils.h @@ -316,7 +316,7 @@ static inline uint32_t ARMExpandImm(uint32_t opcode) // (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in) static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out) { - uint32_t imm32; // the expaned result + uint32_t imm32; // the expanded result const uint32_t i = bit(opcode, 26); const uint32_t imm3 = bits(opcode, 14, 12); const uint32_t abcdefgh = bits(opcode, 7, 0); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp index dc90b7a..3507ccf 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -115,7 +115,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict RegisterInfo reg_info; std::vector<uint32_t> value_regs; std::vector<uint32_t> invalidate_regs; - bzero (®_info, sizeof(reg_info)); + memset(®_info, 0, sizeof(reg_info)); reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString(); if (reg_info.name == NULL) @@ -323,7 +323,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict reg_info.encoding = (Encoding)reg_info_dict.GetItemForKeyAsInteger (encoding_pystr, eEncodingUint); const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1); - if (set >= m_sets.size()) + if (static_cast<size_t>(set) >= m_sets.size()) { Clear(); return 0; @@ -379,7 +379,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict if (invalidate_reg_num) { const int64_t r = invalidate_reg_num.GetInteger(); - if (r != UINT64_MAX) + if (r != static_cast<int64_t>(UINT64_MAX)) m_invalidate_regs_map[i].push_back(r); else printf("error: 'invalidate-regs' list value wasn't a valid integer\n"); @@ -632,10 +632,11 @@ DynamicRegisterInfo::Dump () const { StreamFile s(stdout, false); const size_t num_regs = m_regs.size(); - s.Printf("%p: DynamicRegisterInfo contains %zu registers:\n", this, num_regs); + s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " registers:\n", + static_cast<const void*>(this), static_cast<uint64_t>(num_regs)); for (size_t i=0; i<num_regs; ++i) { - s.Printf("[%3zu] name = %-10s", i, m_regs[i].name); + s.Printf("[%3" PRIu64 "] name = %-10s", (uint64_t)i, m_regs[i].name); s.Printf(", size = %2u, offset = %4u, encoding = %u, format = %-10s", m_regs[i].byte_size, m_regs[i].byte_offset, @@ -671,12 +672,13 @@ DynamicRegisterInfo::Dump () const } s.EOL(); } - + const size_t num_sets = m_sets.size(); - s.Printf("%p: DynamicRegisterInfo contains %zu register sets:\n", this, num_sets); + s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " register sets:\n", + static_cast<const void*>(this), static_cast<uint64_t>(num_sets)); for (size_t i=0; i<num_sets; ++i) { - s.Printf("set[%zu] name = %s, regs = [", i, m_sets[i].name); + s.Printf("set[%" PRIu64 "] name = %s, regs = [", (uint64_t)i, m_sets[i].name); for (size_t idx=0; idx<m_sets[i].num_registers; ++idx) { s.Printf("%s ", m_regs[m_sets[i].registers[idx]].name); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp new file mode 100644 index 0000000..b7c52ae --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp @@ -0,0 +1,31 @@ +//===-- FreeBSDSignals.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "FreeBSDSignals.h" + +FreeBSDSignals::FreeBSDSignals() + : UnixSignals() +{ + Reset(); +} + +void +FreeBSDSignals::Reset() +{ + UnixSignals::Reset(); + + // SIGNO NAME SHORT NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============ ========== ======== ====== ====== =================================================== + AddSignal (32, "SIGTHR", "THR", false, true , true , "thread interrupt"); + AddSignal (33, "SIGLIBRT", "LIBRT", false, true , true , "reserved by real-time library"); +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h new file mode 100644 index 0000000..1e14ccb --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h @@ -0,0 +1,28 @@ +//===-- FreeBSDSignals.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_FreeBSDSignals_H_ +#define liblldb_FreeBSDSignals_H_ + +// Project includes +#include "lldb/Target/UnixSignals.h" + +/// FreeBSD specific set of Unix signals. +class FreeBSDSignals + : public lldb_private::UnixSignals +{ +public: + FreeBSDSignals(); + +private: + void + Reset(); +}; + +#endif // liblldb_FreeBSDSignals_H_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp index d045bc7..590bb01 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp @@ -20,12 +20,14 @@ using namespace lldb; using namespace lldb_private; +// Constructor + HistoryThread::HistoryThread (lldb_private::Process &process, lldb::tid_t tid, std::vector<lldb::addr_t> pcs, uint32_t stop_id, bool stop_id_is_valid) : - Thread (process, tid), + Thread (process, tid, true), m_framelist_mutex(), m_framelist(), m_pcs (pcs), @@ -40,14 +42,18 @@ HistoryThread::HistoryThread (lldb_private::Process &process, m_unwinder_ap.reset (new HistoryUnwind (*this, pcs, stop_id, stop_id_is_valid)); Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) - log->Printf ("%p HistoryThread::HistoryThread", this); + log->Printf ("%p HistoryThread::HistoryThread", + static_cast<void*>(this)); } +// Destructor + HistoryThread::~HistoryThread () { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) - log->Printf ("%p HistoryThread::~HistoryThread (tid=0x%" PRIx64 ")", this, GetID()); + log->Printf ("%p HistoryThread::~HistoryThread (tid=0x%" PRIx64 ")", + static_cast<void*>(this), GetID()); DestroyThread(); } @@ -72,7 +78,7 @@ HistoryThread::CreateRegisterContextForFrame (StackFrame *frame) lldb::StackFrameListSP HistoryThread::GetStackFrameList () { - Mutex::Locker (m_framelist_mutex); + Mutex::Locker (m_framelist_mutex); // FIXME do not throw away the lock after we acquire it.. if (m_framelist.get() == NULL) { m_framelist.reset (new StackFrameList (*this, StackFrameListSP(), true)); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp index 86665fd..f809ebe 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp @@ -20,6 +20,8 @@ using namespace lldb; using namespace lldb_private; +// Constructor + HistoryUnwind::HistoryUnwind (Thread &thread, std::vector<lldb::addr_t> pcs, uint32_t stop_id, @@ -31,6 +33,8 @@ HistoryUnwind::HistoryUnwind (Thread &thread, { } +// Destructor + HistoryUnwind::~HistoryUnwind () { } @@ -62,7 +66,7 @@ HistoryUnwind::DoCreateRegisterContextForFrame (StackFrame *frame) bool HistoryUnwind::DoGetFrameInfoAtIndex (uint32_t frame_idx, lldb::addr_t& cfa, lldb::addr_t& pc) { - Mutex::Locker (m_unwind_mutex); + Mutex::Locker (m_unwind_mutex); // FIXME do not throw away the lock after we acquire it.. if (frame_idx < m_pcs.size()) { cfa = frame_idx; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 1d5d19f..4a94457 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -117,11 +117,11 @@ lldb_private::InferiorCallMmap (Process *process, { ExecutionContext exe_ctx; frame->CalculateExecutionContext (exe_ctx); - ExecutionResults result = process->RunThreadPlan (exe_ctx, + ExpressionResults result = process->RunThreadPlan (exe_ctx, call_plan_sp, options, error_strm); - if (result == eExecutionCompleted) + if (result == eExpressionCompleted) { allocated_addr = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); @@ -202,11 +202,11 @@ lldb_private::InferiorCallMunmap (Process *process, { ExecutionContext exe_ctx; frame->CalculateExecutionContext (exe_ctx); - ExecutionResults result = process->RunThreadPlan (exe_ctx, + ExpressionResults result = process->RunThreadPlan (exe_ctx, call_plan_sp, options, error_strm); - if (result == eExecutionCompleted) + if (result == eExpressionCompleted) { return true; } @@ -260,11 +260,11 @@ lldb_private::InferiorCall (Process *process, { ExecutionContext exe_ctx; frame->CalculateExecutionContext (exe_ctx); - ExecutionResults result = process->RunThreadPlan (exe_ctx, + ExpressionResults result = process->RunThreadPlan (exe_ctx, call_plan_sp, options, error_strm); - if (result == eExecutionCompleted) + if (result == eExpressionCompleted) { returned_func = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InstructionUtils.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InstructionUtils.h index 4bb644e..8139900 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InstructionUtils.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InstructionUtils.h @@ -83,6 +83,8 @@ Rotl32 (uint32_t bits, uint32_t amt) static inline uint64_t MaskUpToBit (const uint64_t bit) { + if (bit >= 63) + return -1ll; return (1ull << (bit + 1ull)) - 1ull; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp new file mode 100644 index 0000000..fb49df6 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -0,0 +1,62 @@ +//===-- LinuxSignals.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "LinuxSignals.h" + +using namespace process_linux; + +LinuxSignals::LinuxSignals() + : UnixSignals() +{ + Reset(); +} + +void +LinuxSignals::Reset() +{ + m_signals.clear(); + + AddSignal (1, "SIGHUP", "HUP", false, true , true , "hangup"); + AddSignal (2, "SIGINT", "INT", true , true , true , "interrupt"); + AddSignal (3, "SIGQUIT", "QUIT", false, true , true , "quit"); + AddSignal (4, "SIGILL", "ILL", false, true , true , "illegal instruction"); + AddSignal (5, "SIGTRAP", "TRAP", true , true , true , "trace trap (not reset when caught)"); + AddSignal (6, "SIGABRT", "ABRT", false, true , true , "abort()"); + AddSignal (6, "SIGIOT", "IOT", false, true , true , "IOT trap"); + AddSignal (7, "SIGBUS", "BUS", false, true , true , "bus error"); + AddSignal (8, "SIGFPE", "FPE", false, true , true , "floating point exception"); + AddSignal (9, "SIGKILL", "KILL", false, true , true , "kill"); + AddSignal (10, "SIGUSR1", "USR1", false, true , true , "user defined signal 1"); + AddSignal (11, "SIGSEGV", "SEGV", false, true , true , "segmentation violation"); + AddSignal (12, "SIGUSR2", "USR2", false, true , true , "user defined signal 2"); + AddSignal (13, "SIGPIPE", "PIPE", false, true , true , "write to pipe with reading end closed"); + AddSignal (14, "SIGALRM", "ALRM", false, false, false, "alarm"); + AddSignal (15, "SIGTERM", "TERM", false, true , true , "termination requested"); + AddSignal (16, "SIGSTKFLT", "STKFLT", false, true , true , "stack fault"); + AddSignal (16, "SIGCLD", "CLD", false, false, true , "same as SIGCHLD"); + AddSignal (17, "SIGCHLD", "CHLD", false, false, true , "child status has changed"); + AddSignal (18, "SIGCONT", "CONT", false, true , true , "process continue"); + AddSignal (19, "SIGSTOP", "STOP", true , true , true , "process stop"); + AddSignal (20, "SIGTSTP", "TSTP", false, true , true , "tty stop"); + AddSignal (21, "SIGTTIN", "TTIN", false, true , true , "background tty read"); + AddSignal (22, "SIGTTOU", "TTOU", false, true , true , "background tty write"); + AddSignal (23, "SIGURG", "URG", false, true , true , "urgent data on socket"); + AddSignal (24, "SIGXCPU", "XCPU", false, true , true , "CPU resource exceeded"); + AddSignal (25, "SIGXFSZ", "XFSZ", false, true , true , "file size limit exceeded"); + AddSignal (26, "SIGVTALRM", "VTALRM", false, true , true , "virtual time alarm"); + AddSignal (27, "SIGPROF", "PROF", false, true , true , "profiling time alarm"); + AddSignal (28, "SIGWINCH", "WINCH", false, true , true , "window size changes"); + AddSignal (29, "SIGPOLL", "POLL", false, true , true , "pollable event"); + AddSignal (29, "SIGIO", "IO", false, true , true , "input/output ready"); + AddSignal (30, "SIGPWR", "PWR", false, true , true , "power failure"); + AddSignal (31, "SIGSYS", "SYS", false, true , true , "invalid system call"); +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.h new file mode 100644 index 0000000..9645b3d --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.h @@ -0,0 +1,35 @@ +//===-- LinuxSignals.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_LinuxSignals_H_ +#define liblldb_LinuxSignals_H_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Target/UnixSignals.h" + +namespace process_linux +{ + + /// Linux specific set of Unix signals. + class LinuxSignals + : public lldb_private::UnixSignals + { + public: + LinuxSignals(); + + private: + void + Reset(); + }; +} + +#endif diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp index 4d77b6f..4138a6a 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp @@ -37,6 +37,8 @@ #include "ARM_GCC_Registers.h" #include "ARM_DWARF_Registers.h" +#include "llvm/ADT/STLExtras.h" + using namespace lldb; using namespace lldb_private; @@ -399,7 +401,7 @@ g_exc_regnums[] = exc_far, }; -static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo)); +static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos); void RegisterContextDarwin_arm::InvalidateAllRegisters () @@ -438,9 +440,9 @@ RegisterContextDarwin_arm::GetRegisterInfos () // Number of registers in each register set -const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t); -const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t); -const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t); +const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums); +const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); +const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); //---------------------------------------------------------------------- // Register set definitions. The first definitions at register set index @@ -454,7 +456,7 @@ static const RegisterSet g_reg_sets[] = { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums } }; -const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet); +const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets); size_t @@ -473,7 +475,7 @@ RegisterContextDarwin_arm::GetRegisterSet (size_t reg_set) //---------------------------------------------------------------------- -// Register information defintions for 32 bit i386. +// Register information definitions for 32 bit i386. //---------------------------------------------------------------------- int RegisterContextDarwin_arm::GetSetForNativeRegNum (int reg) @@ -864,7 +866,7 @@ RegisterContextDarwin_arm::WriteAllRegisterValues (const lldb::DataBufferSP &dat } uint32_t -RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg) +RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg) { if (kind == eRegisterKindGeneric) { diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h index 0bf204f..23134ef 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h @@ -87,7 +87,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); virtual uint32_t NumSupportedHardwareBreakpoints (); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp new file mode 100644 index 0000000..e08a873 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp @@ -0,0 +1,944 @@ +//===-- RegisterContextDarwin_arm64.cpp ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#if defined(__APPLE__) + +#include "RegisterContextDarwin_arm64.h" + +// C Includes +#include <mach/mach_types.h> +#include <mach/thread_act.h> +#include <sys/sysctl.h> + +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Host/Endian.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Compiler.h" + +#include "Plugins/Process/Utility/InstructionUtils.h" + +// Support building against older versions of LLVM, this macro was added +// recently. +#ifndef LLVM_EXTENSION +#define LLVM_EXTENSION +#endif + +// Project includes +#include "ARM64_GCC_Registers.h" +#include "ARM64_DWARF_Registers.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextDarwin_arm64::RegisterContextDarwin_arm64(Thread &thread, uint32_t concrete_frame_idx) : + RegisterContext(thread, concrete_frame_idx), + gpr(), + fpu(), + exc() +{ + uint32_t i; + for (i=0; i<kNumErrors; i++) + { + gpr_errs[i] = -1; + fpu_errs[i] = -1; + exc_errs[i] = -1; + } +} + +RegisterContextDarwin_arm64::~RegisterContextDarwin_arm64() +{ +} + + +#define GPR_OFFSET(idx) ((idx) * 8) +#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::GPR, reg)) + +#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextDarwin_arm64::GPR)) +#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::FPU, reg)) + +#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::EXC, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU)) +#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::DBG, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC)) + +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC)) + +//----------------------------------------------------------------------------- +// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. +//----------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_ARM64_STRUCT +#include "RegisterInfos_arm64.h" +#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT + +// General purpose registers +static uint32_t +g_gpr_regnums[] = +{ + gpr_x0, + gpr_x1, + gpr_x2, + gpr_x3, + gpr_x4, + gpr_x5, + gpr_x6, + gpr_x7, + gpr_x8, + gpr_x9, + gpr_x10, + gpr_x11, + gpr_x12, + gpr_x13, + gpr_x14, + gpr_x15, + gpr_x16, + gpr_x17, + gpr_x18, + gpr_x19, + gpr_x20, + gpr_x21, + gpr_x22, + gpr_x23, + gpr_x24, + gpr_x25, + gpr_x26, + gpr_x27, + gpr_x28, + gpr_fp, + gpr_lr, + gpr_sp, + gpr_pc, + gpr_cpsr +}; + +// Floating point registers +static uint32_t +g_fpu_regnums[] = +{ + fpu_v0, + fpu_v1, + fpu_v2, + fpu_v3, + fpu_v4, + fpu_v5, + fpu_v6, + fpu_v7, + fpu_v8, + fpu_v9, + fpu_v10, + fpu_v11, + fpu_v12, + fpu_v13, + fpu_v14, + fpu_v15, + fpu_v16, + fpu_v17, + fpu_v18, + fpu_v19, + fpu_v20, + fpu_v21, + fpu_v22, + fpu_v23, + fpu_v24, + fpu_v25, + fpu_v26, + fpu_v27, + fpu_v28, + fpu_v29, + fpu_v30, + fpu_v31, + fpu_fpsr, + fpu_fpcr +}; + +// Exception registers + +static uint32_t +g_exc_regnums[] = +{ + exc_far, + exc_esr, + exc_exception +}; + +static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos_arm64); + +void +RegisterContextDarwin_arm64::InvalidateAllRegisters () +{ + InvalidateAllRegisterStates(); +} + + +size_t +RegisterContextDarwin_arm64::GetRegisterCount () +{ + assert(k_num_register_infos == k_num_registers); + return k_num_registers; +} + +const RegisterInfo * +RegisterContextDarwin_arm64::GetRegisterInfoAtIndex (size_t reg) +{ + assert(k_num_register_infos == k_num_registers); + if (reg < k_num_registers) + return &g_register_infos_arm64[reg]; + return NULL; +} + +size_t +RegisterContextDarwin_arm64::GetRegisterInfosCount () +{ + return k_num_register_infos; +} + +const RegisterInfo * +RegisterContextDarwin_arm64::GetRegisterInfos () +{ + return g_register_infos_arm64; +} + + +// Number of registers in each register set +const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums); +const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); +const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); + +//---------------------------------------------------------------------- +// Register set definitions. The first definitions at register set index +// of zero is for all registers, followed by other registers sets. The +// register information for the all register set need not be filled in. +//---------------------------------------------------------------------- +static const RegisterSet g_reg_sets[] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, }, + { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums }, + { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums } +}; + +const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets); + + +size_t +RegisterContextDarwin_arm64::GetRegisterSetCount () +{ + return k_num_regsets; +} + +const RegisterSet * +RegisterContextDarwin_arm64::GetRegisterSet (size_t reg_set) +{ + if (reg_set < k_num_regsets) + return &g_reg_sets[reg_set]; + return NULL; +} + + +//---------------------------------------------------------------------- +// Register information definitions for arm64 +//---------------------------------------------------------------------- +int +RegisterContextDarwin_arm64::GetSetForNativeRegNum (int reg) +{ + if (reg < fpu_v0) + return GPRRegSet; + else if (reg < exc_far) + return FPURegSet; + else if (reg < k_num_registers) + return EXCRegSet; + return -1; +} + +int +RegisterContextDarwin_arm64::ReadGPR (bool force) +{ + int set = GPRRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr)); + } + return GetError(GPRRegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadFPU (bool force) +{ + int set = FPURegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu)); + } + return GetError(FPURegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadEXC (bool force) +{ + int set = EXCRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadEXC(GetThreadID(), set, exc)); + } + return GetError(EXCRegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadDBG (bool force) +{ + int set = DBGRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg)); + } + return GetError(DBGRegSet, Read); +} + +int +RegisterContextDarwin_arm64::WriteGPR () +{ + int set = GPRRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr)); + SetError (set, Read, -1); + return GetError(GPRRegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteFPU () +{ + int set = FPURegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu)); + SetError (set, Read, -1); + return GetError(FPURegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteEXC () +{ + int set = EXCRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc)); + SetError (set, Read, -1); + return GetError(EXCRegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteDBG () +{ + int set = DBGRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteDBG(GetThreadID(), set, dbg)); + SetError (set, Read, -1); + return GetError(DBGRegSet, Write); +} + + +int +RegisterContextDarwin_arm64::ReadRegisterSet (uint32_t set, bool force) +{ + switch (set) + { + case GPRRegSet: return ReadGPR(force); + case FPURegSet: return ReadFPU(force); + case EXCRegSet: return ReadEXC(force); + case DBGRegSet: return ReadDBG(force); + default: break; + } + return KERN_INVALID_ARGUMENT; +} + +int +RegisterContextDarwin_arm64::WriteRegisterSet (uint32_t set) +{ + // Make sure we have a valid context to set. + if (RegisterSetIsCached(set)) + { + switch (set) + { + case GPRRegSet: return WriteGPR(); + case FPURegSet: return WriteFPU(); + case EXCRegSet: return WriteEXC(); + case DBGRegSet: return WriteDBG(); + default: break; + } + } + return KERN_INVALID_ARGUMENT; +} + +void +RegisterContextDarwin_arm64::LogDBGRegisters (Log *log, const DBG& dbg) +{ + if (log) + { + for (uint32_t i=0; i<16; i++) + log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8llx, 0x%8.8llx } WVR%-2u/WCR%-2u = { 0x%8.8llx, 0x%8.8llx }", + i, i, dbg.bvr[i], dbg.bcr[i], + i, i, dbg.wvr[i], dbg.wcr[i]); + } +} + + +bool +RegisterContextDarwin_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + int set = RegisterContextDarwin_arm64::GetSetForNativeRegNum (reg); + + if (set == -1) + return false; + + if (ReadRegisterSet(set, false) != KERN_SUCCESS) + return false; + + switch (reg) + { + case gpr_x0: + case gpr_x1: + case gpr_x2: + case gpr_x3: + case gpr_x4: + case gpr_x5: + case gpr_x6: + case gpr_x7: + case gpr_x8: + case gpr_x9: + case gpr_x10: + case gpr_x11: + case gpr_x12: + case gpr_x13: + case gpr_x14: + case gpr_x15: + case gpr_x16: + case gpr_x17: + case gpr_x18: + case gpr_x19: + case gpr_x20: + case gpr_x21: + case gpr_x22: + case gpr_x23: + case gpr_x24: + case gpr_x25: + case gpr_x26: + case gpr_x27: + case gpr_x28: + case gpr_fp: + case gpr_sp: + case gpr_lr: + case gpr_pc: + case gpr_cpsr: + value.SetUInt64 (gpr.x[reg - gpr_x0]); + break; + + case fpu_v0: + case fpu_v1: + case fpu_v2: + case fpu_v3: + case fpu_v4: + case fpu_v5: + case fpu_v6: + case fpu_v7: + case fpu_v8: + case fpu_v9: + case fpu_v10: + case fpu_v11: + case fpu_v12: + case fpu_v13: + case fpu_v14: + case fpu_v15: + case fpu_v16: + case fpu_v17: + case fpu_v18: + case fpu_v19: + case fpu_v20: + case fpu_v21: + case fpu_v22: + case fpu_v23: + case fpu_v24: + case fpu_v25: + case fpu_v26: + case fpu_v27: + case fpu_v28: + case fpu_v29: + case fpu_v30: + case fpu_v31: + value.SetBytes(fpu.v[reg].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder()); + break; + + case fpu_fpsr: + value.SetUInt32 (fpu.fpsr); + break; + + case fpu_fpcr: + value.SetUInt32 (fpu.fpcr); + break; + + case exc_exception: + value.SetUInt32 (exc.exception); + break; + case exc_esr: + value.SetUInt32 (exc.esr); + break; + case exc_far: + value.SetUInt64 (exc.far); + break; + + default: + value.SetValueToInvalid(); + return false; + + } + return true; +} + + +bool +RegisterContextDarwin_arm64::WriteRegister (const RegisterInfo *reg_info, + const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + int set = GetSetForNativeRegNum (reg); + + if (set == -1) + return false; + + if (ReadRegisterSet(set, false) != KERN_SUCCESS) + return false; + + switch (reg) + { + case gpr_x0: + case gpr_x1: + case gpr_x2: + case gpr_x3: + case gpr_x4: + case gpr_x5: + case gpr_x6: + case gpr_x7: + case gpr_x8: + case gpr_x9: + case gpr_x10: + case gpr_x11: + case gpr_x12: + case gpr_x13: + case gpr_x14: + case gpr_x15: + case gpr_x16: + case gpr_x17: + case gpr_x18: + case gpr_x19: + case gpr_x20: + case gpr_x21: + case gpr_x22: + case gpr_x23: + case gpr_x24: + case gpr_x25: + case gpr_x26: + case gpr_x27: + case gpr_x28: + case gpr_fp: + case gpr_sp: + case gpr_lr: + case gpr_pc: + case gpr_cpsr: + gpr.x[reg - gpr_x0] = value.GetAsUInt64(); + break; + + case fpu_v0: + case fpu_v1: + case fpu_v2: + case fpu_v3: + case fpu_v4: + case fpu_v5: + case fpu_v6: + case fpu_v7: + case fpu_v8: + case fpu_v9: + case fpu_v10: + case fpu_v11: + case fpu_v12: + case fpu_v13: + case fpu_v14: + case fpu_v15: + case fpu_v16: + case fpu_v17: + case fpu_v18: + case fpu_v19: + case fpu_v20: + case fpu_v21: + case fpu_v22: + case fpu_v23: + case fpu_v24: + case fpu_v25: + case fpu_v26: + case fpu_v27: + case fpu_v28: + case fpu_v29: + case fpu_v30: + case fpu_v31: + ::memcpy (fpu.v[reg].bytes, value.GetBytes(), value.GetByteSize()); + break; + + case fpu_fpsr: + fpu.fpsr = value.GetAsUInt32(); + break; + + case fpu_fpcr: + fpu.fpcr = value.GetAsUInt32(); + break; + + case exc_exception: + exc.exception = value.GetAsUInt32(); + break; + case exc_esr: + exc.esr = value.GetAsUInt32(); + break; + case exc_far: + exc.far = value.GetAsUInt64(); + break; + + default: + return false; + + } + return WriteRegisterSet(set) == KERN_SUCCESS; +} + +bool +RegisterContextDarwin_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) +{ + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && + ReadGPR (false) == KERN_SUCCESS && + ReadFPU (false) == KERN_SUCCESS && + ReadEXC (false) == KERN_SUCCESS) + { + uint8_t *dst = data_sp->GetBytes(); + ::memcpy (dst, &gpr, sizeof(gpr)); + dst += sizeof(gpr); + + ::memcpy (dst, &fpu, sizeof(fpu)); + dst += sizeof(gpr); + + ::memcpy (dst, &exc, sizeof(exc)); + return true; + } + return false; +} + +bool +RegisterContextDarwin_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) +{ + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + const uint8_t *src = data_sp->GetBytes(); + ::memcpy (&gpr, src, sizeof(gpr)); + src += sizeof(gpr); + + ::memcpy (&fpu, src, sizeof(fpu)); + src += sizeof(gpr); + + ::memcpy (&exc, src, sizeof(exc)); + uint32_t success_count = 0; + if (WriteGPR() == KERN_SUCCESS) + ++success_count; + if (WriteFPU() == KERN_SUCCESS) + ++success_count; + if (WriteEXC() == KERN_SUCCESS) + ++success_count; + return success_count == 3; + } + return false; +} + +uint32_t +RegisterContextDarwin_arm64::ConvertRegisterKindToRegisterNumber (RegisterKind kind, uint32_t reg) +{ + if (kind == eRegisterKindGeneric) + { + switch (reg) + { + case LLDB_REGNUM_GENERIC_PC: return gpr_pc; + case LLDB_REGNUM_GENERIC_SP: return gpr_sp; + case LLDB_REGNUM_GENERIC_FP: return gpr_fp; + case LLDB_REGNUM_GENERIC_RA: return gpr_lr; + case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr; + default: + break; + } + } + else if (kind == eRegisterKindDWARF) + { + switch (reg) + { + case arm64_dwarf::x0: return gpr_x0; + case arm64_dwarf::x1: return gpr_x1; + case arm64_dwarf::x2: return gpr_x2; + case arm64_dwarf::x3: return gpr_x3; + case arm64_dwarf::x4: return gpr_x4; + case arm64_dwarf::x5: return gpr_x5; + case arm64_dwarf::x6: return gpr_x6; + case arm64_dwarf::x7: return gpr_x7; + case arm64_dwarf::x8: return gpr_x8; + case arm64_dwarf::x9: return gpr_x9; + case arm64_dwarf::x10: return gpr_x10; + case arm64_dwarf::x11: return gpr_x11; + case arm64_dwarf::x12: return gpr_x12; + case arm64_dwarf::x13: return gpr_x13; + case arm64_dwarf::x14: return gpr_x14; + case arm64_dwarf::x15: return gpr_x15; + case arm64_dwarf::x16: return gpr_x16; + case arm64_dwarf::x17: return gpr_x17; + case arm64_dwarf::x18: return gpr_x18; + case arm64_dwarf::x19: return gpr_x19; + case arm64_dwarf::x20: return gpr_x20; + case arm64_dwarf::x21: return gpr_x21; + case arm64_dwarf::x22: return gpr_x22; + case arm64_dwarf::x23: return gpr_x23; + case arm64_dwarf::x24: return gpr_x24; + case arm64_dwarf::x25: return gpr_x25; + case arm64_dwarf::x26: return gpr_x26; + case arm64_dwarf::x27: return gpr_x27; + case arm64_dwarf::x28: return gpr_x28; + + case arm64_dwarf::fp: return gpr_fp; + case arm64_dwarf::sp: return gpr_sp; + case arm64_dwarf::lr: return gpr_lr; + case arm64_dwarf::pc: return gpr_pc; + case arm64_dwarf::cpsr: return gpr_cpsr; + + case arm64_dwarf::v0: return fpu_v0; + case arm64_dwarf::v1: return fpu_v1; + case arm64_dwarf::v2: return fpu_v2; + case arm64_dwarf::v3: return fpu_v3; + case arm64_dwarf::v4: return fpu_v4; + case arm64_dwarf::v5: return fpu_v5; + case arm64_dwarf::v6: return fpu_v6; + case arm64_dwarf::v7: return fpu_v7; + case arm64_dwarf::v8: return fpu_v8; + case arm64_dwarf::v9: return fpu_v9; + case arm64_dwarf::v10: return fpu_v10; + case arm64_dwarf::v11: return fpu_v11; + case arm64_dwarf::v12: return fpu_v12; + case arm64_dwarf::v13: return fpu_v13; + case arm64_dwarf::v14: return fpu_v14; + case arm64_dwarf::v15: return fpu_v15; + case arm64_dwarf::v16: return fpu_v16; + case arm64_dwarf::v17: return fpu_v17; + case arm64_dwarf::v18: return fpu_v18; + case arm64_dwarf::v19: return fpu_v19; + case arm64_dwarf::v20: return fpu_v20; + case arm64_dwarf::v21: return fpu_v21; + case arm64_dwarf::v22: return fpu_v22; + case arm64_dwarf::v23: return fpu_v23; + case arm64_dwarf::v24: return fpu_v24; + case arm64_dwarf::v25: return fpu_v25; + case arm64_dwarf::v26: return fpu_v26; + case arm64_dwarf::v27: return fpu_v27; + case arm64_dwarf::v28: return fpu_v28; + case arm64_dwarf::v29: return fpu_v29; + case arm64_dwarf::v30: return fpu_v30; + case arm64_dwarf::v31: return fpu_v31; + + default: + break; + } + } + else if (kind == eRegisterKindGCC) + { + switch (reg) + { + case arm64_gcc::x0: return gpr_x0; + case arm64_gcc::x1: return gpr_x1; + case arm64_gcc::x2: return gpr_x2; + case arm64_gcc::x3: return gpr_x3; + case arm64_gcc::x4: return gpr_x4; + case arm64_gcc::x5: return gpr_x5; + case arm64_gcc::x6: return gpr_x6; + case arm64_gcc::x7: return gpr_x7; + case arm64_gcc::x8: return gpr_x8; + case arm64_gcc::x9: return gpr_x9; + case arm64_gcc::x10: return gpr_x10; + case arm64_gcc::x11: return gpr_x11; + case arm64_gcc::x12: return gpr_x12; + case arm64_gcc::x13: return gpr_x13; + case arm64_gcc::x14: return gpr_x14; + case arm64_gcc::x15: return gpr_x15; + case arm64_gcc::x16: return gpr_x16; + case arm64_gcc::x17: return gpr_x17; + case arm64_gcc::x18: return gpr_x18; + case arm64_gcc::x19: return gpr_x19; + case arm64_gcc::x20: return gpr_x20; + case arm64_gcc::x21: return gpr_x21; + case arm64_gcc::x22: return gpr_x22; + case arm64_gcc::x23: return gpr_x23; + case arm64_gcc::x24: return gpr_x24; + case arm64_gcc::x25: return gpr_x25; + case arm64_gcc::x26: return gpr_x26; + case arm64_gcc::x27: return gpr_x27; + case arm64_gcc::x28: return gpr_x28; + case arm64_gcc::fp: return gpr_fp; + case arm64_gcc::sp: return gpr_sp; + case arm64_gcc::lr: return gpr_lr; + case arm64_gcc::pc: return gpr_pc; + case arm64_gcc::cpsr: return gpr_cpsr; + } + } + else if (kind == eRegisterKindLLDB) + { + return reg; + } + return LLDB_INVALID_REGNUM; +} + + +uint32_t +RegisterContextDarwin_arm64::NumSupportedHardwareWatchpoints () +{ +#if defined (__arm64__) || defined (__aarch64__) + // autodetect how many watchpoints are supported dynamically... + static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX; + if (g_num_supported_hw_watchpoints == UINT32_MAX) + { + size_t len; + uint32_t n = 0; + len = sizeof (n); + if (::sysctlbyname("hw.optional.watchpoint", &n, &len, NULL, 0) == 0) + { + g_num_supported_hw_watchpoints = n; + } + } + return g_num_supported_hw_watchpoints; +#else + // TODO: figure out remote case here! + return 2; +#endif +} + + +uint32_t +RegisterContextDarwin_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write) +{ +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write); + + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + + // Can't watch zero bytes + if (size == 0) + return LLDB_INVALID_INDEX32; + + // We must watch for either read or write + if (read == false && write == false) + return LLDB_INVALID_INDEX32; + + // Can't watch more than 4 bytes per WVR/WCR pair + if (size > 4) + return LLDB_INVALID_INDEX32; + + // We can only watch up to four bytes that follow a 4 byte aligned address + // per watchpoint register pair. Since we have at most so we can only watch + // until the next 4 byte boundary and we need to make sure we can properly + // encode this. + uint32_t addr_word_offset = addr % 4; +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset); + + uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset; +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask); + if (byte_mask > 0xfu) + return LLDB_INVALID_INDEX32; + + // Read the debug state + int kret = ReadDBG (false); + + if (kret == KERN_SUCCESS) + { + // Check to make sure we have the needed hardware support + uint32_t i = 0; + + for (i=0; i<num_hw_watchpoints; ++i) + { + if ((dbg.wcr[i] & WCR_ENABLE) == 0) + break; // We found an available hw breakpoint slot (in i) + } + + // See if we found an available hw breakpoint slot above + if (i < num_hw_watchpoints) + { + // Make the byte_mask into a valid Byte Address Select mask + uint32_t byte_address_select = byte_mask << 5; + // Make sure bits 1:0 are clear in our address + dbg.wvr[i] = addr & ~((lldb::addr_t)3); + dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA that we will watch + S_USER | // Stop only in user mode + (read ? WCR_LOAD : 0) | // Stop on read access? + (write ? WCR_STORE : 0) | // Stop on write access? + WCR_ENABLE; // Enable this watchpoint; + + kret = WriteDBG(); +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret); + + if (kret == KERN_SUCCESS) + return i; + } + else + { +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); + } + } + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextDarwin_arm64::ClearHardwareWatchpoint (uint32_t hw_index) +{ + int kret = ReadDBG (false); + + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (kret == KERN_SUCCESS) + { + if (hw_index < num_hw_points) + { + dbg.wcr[hw_index] = 0; +// if (log) log->Printf ("RegisterContextDarwin_arm64::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x", +// hw_index, +// hw_index, +// dbg.wvr[hw_index], +// hw_index, +// dbg.wcr[hw_index]); + + kret = WriteDBG(); + + if (kret == KERN_SUCCESS) + return true; + } + } + return false; +} + +#endif diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h new file mode 100644 index 0000000..aeac15e --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h @@ -0,0 +1,296 @@ +//===-- RegisterContextDarwin_arm64.h -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextDarwin_arm64_h_ +#define liblldb_RegisterContextDarwin_arm64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" + +// Break only in privileged or user mode +#define S_RSVD ((uint32_t)(0u << 1)) +#define S_PRIV ((uint32_t)(1u << 1)) +#define S_USER ((uint32_t)(2u << 1)) +#define S_PRIV_USER ((S_PRIV) | (S_USER)) + +#define WCR_ENABLE ((uint32_t)(1u)) + +// Watchpoint load/store +#define WCR_LOAD ((uint32_t)(1u << 3)) +#define WCR_STORE ((uint32_t)(1u << 4)) + +class RegisterContextDarwin_arm64 : public lldb_private::RegisterContext +{ +public: + + RegisterContextDarwin_arm64(lldb_private::Thread &thread, uint32_t concrete_frame_idx); + + virtual + ~RegisterContextDarwin_arm64(); + + virtual void + InvalidateAllRegisters (); + + virtual size_t + GetRegisterCount (); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex (size_t reg); + + virtual size_t + GetRegisterSetCount (); + + virtual const lldb_private::RegisterSet * + GetRegisterSet (size_t set); + + virtual bool + ReadRegister (const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue ®_value); + + virtual bool + WriteRegister (const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue ®_value); + + virtual bool + ReadAllRegisterValues (lldb::DataBufferSP &data_sp); + + virtual bool + WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); + + virtual uint32_t + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); + + virtual uint32_t + NumSupportedHardwareWatchpoints (); + + virtual uint32_t + SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write); + + virtual bool + ClearHardwareWatchpoint (uint32_t hw_index); + + // mirrors <mach/arm/thread_status.h> arm_thread_state64_t + struct GPR + { + uint64_t x[29]; // x0-x28 + uint64_t fp; // x29 + uint64_t lr; // x30 + uint64_t sp; // x31 + uint64_t pc; // pc + uint32_t cpsr; // cpsr + }; + + + struct VReg + { + uint8_t bytes[16]; + }; + + // mirrors <mach/arm/thread_status.h> arm_neon_state64_t + struct FPU + { + VReg v[32]; + uint32_t fpsr; + uint32_t fpcr; + }; + + // mirrors <mach/arm/thread_status.h> arm_exception_state64_t + struct EXC + { + uint64_t far; // Virtual Fault Address + uint32_t esr; // Exception syndrome + uint32_t exception; // number of arm exception token + }; + + // mirrors <mach/arm/thread_status.h> arm_debug_state64_t + struct DBG + { + uint64_t bvr[16]; + uint64_t bcr[16]; + uint64_t wvr[16]; + uint64_t wcr[16]; + uint64_t mdscr_el1; + }; + + static void + LogDBGRegisters (lldb_private::Log *log, const DBG& dbg); + +protected: + + enum + { + GPRRegSet = 6, // ARM_THREAD_STATE64 + FPURegSet = 17, // ARM_NEON_STATE64 + EXCRegSet = 7, // ARM_EXCEPTION_STATE64 + DBGRegSet = 15 // ARM_DEBUG_STATE64 + }; + + enum + { + GPRWordCount = sizeof(GPR)/sizeof(uint32_t), // ARM_THREAD_STATE64_COUNT + FPUWordCount = sizeof(FPU)/sizeof(uint32_t), // ARM_NEON_STATE64_COUNT + EXCWordCount = sizeof(EXC)/sizeof(uint32_t), // ARM_EXCEPTION_STATE64_COUNT + DBGWordCount = sizeof(DBG)/sizeof(uint32_t) // ARM_DEBUG_STATE64_COUNT + }; + + enum + { + Read = 0, + Write = 1, + kNumErrors = 2 + }; + + GPR gpr; + FPU fpu; + EXC exc; + DBG dbg; + int gpr_errs[2]; // Read/Write errors + int fpu_errs[2]; // Read/Write errors + int exc_errs[2]; // Read/Write errors + int dbg_errs[2]; // Read/Write errors + + void + InvalidateAllRegisterStates() + { + SetError (GPRRegSet, Read, -1); + SetError (FPURegSet, Read, -1); + SetError (EXCRegSet, Read, -1); + } + + int + GetError (int flavor, uint32_t err_idx) const + { + if (err_idx < kNumErrors) + { + switch (flavor) + { + // When getting all errors, just OR all values together to see if + // we got any kind of error. + case GPRRegSet: return gpr_errs[err_idx]; + case FPURegSet: return fpu_errs[err_idx]; + case EXCRegSet: return exc_errs[err_idx]; + case DBGRegSet: return dbg_errs[err_idx]; + default: break; + } + } + return -1; + } + + bool + SetError (int flavor, uint32_t err_idx, int err) + { + if (err_idx < kNumErrors) + { + switch (flavor) + { + case GPRRegSet: + gpr_errs[err_idx] = err; + return true; + + case FPURegSet: + fpu_errs[err_idx] = err; + return true; + + case EXCRegSet: + exc_errs[err_idx] = err; + return true; + + case DBGRegSet: + exc_errs[err_idx] = err; + return true; + + default: break; + } + } + return false; + } + + bool + RegisterSetIsCached (int set) const + { + return GetError(set, Read) == 0; + } + + int + ReadGPR (bool force); + + int + ReadFPU (bool force); + + int + ReadEXC (bool force); + + int + ReadDBG (bool force); + + int + WriteGPR (); + + int + WriteFPU (); + + int + WriteEXC (); + + int + WriteDBG (); + + + // Subclasses override these to do the actual reading. + virtual int + DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) + { + return -1; + } + + virtual int + DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0; + + virtual int + DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0; + + virtual int + DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) = 0; + + virtual int + DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0; + + virtual int + DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0; + + virtual int + DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0; + + virtual int + DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) = 0; + + int + ReadRegisterSet (uint32_t set, bool force); + + int + WriteRegisterSet (uint32_t set); + + static uint32_t + GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num); + + static int + GetSetForNativeRegNum (int reg_num); + + static size_t + GetRegisterInfosCount (); + + static const lldb_private::RegisterInfo * + GetRegisterInfos (); +}; + +#endif // liblldb_RegisterContextDarwin_arm64_h_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp index a94d1f5..08144bf 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Host/Endian.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" // Support building against older versions of LLVM, this macro was added @@ -281,7 +282,7 @@ static RegisterInfo g_register_infos[] = { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL} }; -static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo)); +static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos); void RegisterContextDarwin_i386::InvalidateAllRegisters () @@ -384,9 +385,9 @@ g_exc_regnums[] = }; // Number of registers in each register set -const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t); -const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t); -const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t); +const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums); +const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); +const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); //---------------------------------------------------------------------- // Register set definitions. The first definitions at register set index @@ -400,7 +401,7 @@ static const RegisterSet g_reg_sets[] = { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums } }; -const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet); +const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets); size_t @@ -843,7 +844,7 @@ RegisterContextDarwin_i386::WriteAllRegisterValues (const lldb::DataBufferSP &da uint32_t -RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg) +RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg) { if (kind == eRegisterKindGeneric) { diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h index a588494..1d03feb 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h @@ -55,7 +55,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); virtual bool HardwareSingleStep (bool enable); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp index 433782f..54124d1 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp @@ -9,6 +9,7 @@ // C Includes +#include <inttypes.h> // PRIx64 #include <stdarg.h> #include <stddef.h> // offsetof @@ -20,6 +21,7 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Host/Endian.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" // Support building against older versions of LLVM, this macro was added @@ -317,7 +319,7 @@ static RegisterInfo g_register_infos[] = { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL} }; -static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo)); +static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos); void @@ -431,9 +433,9 @@ g_exc_regnums[] = }; // Number of registers in each register set -const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t); -const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t); -const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t); +const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums); +const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums); +const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums); //---------------------------------------------------------------------- // Register set definitions. The first definitions at register set index @@ -447,7 +449,7 @@ static const RegisterSet g_reg_sets[] = { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums } }; -const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet); +const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets); size_t @@ -902,7 +904,7 @@ RegisterContextDarwin_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP & uint32_t -RegisterContextDarwin_x86_64::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg) +RegisterContextDarwin_x86_64::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg) { if (kind == eRegisterKindGeneric) { diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h index 4b8127a..09e35e9 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h @@ -54,7 +54,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); virtual bool HardwareSingleStep (bool enable); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp index 1e282ce..329b0a7 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp @@ -129,7 +129,7 @@ RegisterContextDummy::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) } uint32_t -RegisterContextDummy::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextDummy::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC) return 0; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h index ee8d5a1..ddf4667 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h @@ -60,7 +60,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); private: //------------------------------------------------------------------ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp index 01c9bb4..185ba26 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp @@ -62,27 +62,27 @@ RegisterContextFreeBSD_i386::RegisterContextFreeBSD_i386(const ArchSpec &target_ { } -RegisterContextFreeBSD_i386::~RegisterContextFreeBSD_i386() -{ -} - size_t -RegisterContextFreeBSD_i386::GetGPRSize() +RegisterContextFreeBSD_i386::GetGPRSize() const { return sizeof(GPR); } const RegisterInfo * -RegisterContextFreeBSD_i386::GetRegisterInfo() +RegisterContextFreeBSD_i386::GetRegisterInfo() const { - switch (m_target_arch.GetCore()) + switch (m_target_arch.GetMachine()) { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: + case llvm::Triple::x86: return g_register_infos_i386; default: assert(false && "Unhandled target architecture."); return NULL; } } + +uint32_t +RegisterContextFreeBSD_i386::GetRegisterCount () const +{ + return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0])); +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h index 4ec2ad3..62792c0 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h @@ -13,17 +13,19 @@ #include "RegisterContextPOSIX.h" class RegisterContextFreeBSD_i386 - : public RegisterInfoInterface + : public lldb_private::RegisterInfoInterface { public: RegisterContextFreeBSD_i386(const lldb_private::ArchSpec &target_arch); - virtual ~RegisterContextFreeBSD_i386(); size_t - GetGPRSize(); + GetGPRSize() const override; const lldb_private::RegisterInfo * - GetRegisterInfo(); + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; }; #endif diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp index 4714251..c31b0ee 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp @@ -71,20 +71,23 @@ RegisterContextFreeBSD_mips64::RegisterContextFreeBSD_mips64(const ArchSpec &tar { } -RegisterContextFreeBSD_mips64::~RegisterContextFreeBSD_mips64() -{ -} - size_t -RegisterContextFreeBSD_mips64::GetGPRSize() +RegisterContextFreeBSD_mips64::GetGPRSize() const { return sizeof(GPR); } const RegisterInfo * -RegisterContextFreeBSD_mips64::GetRegisterInfo() +RegisterContextFreeBSD_mips64::GetRegisterInfo() const { assert (m_target_arch.GetCore() == ArchSpec::eCore_mips64); return g_register_infos_mips64; } +uint32_t +RegisterContextFreeBSD_mips64::GetRegisterCount () const +{ + return static_cast<uint32_t> (sizeof (g_register_infos_mips64) / sizeof (g_register_infos_mips64 [0])); +} + + diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h index 9ee7679..f9a3ce0 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h @@ -13,17 +13,19 @@ #include "RegisterContextPOSIX.h" class RegisterContextFreeBSD_mips64: - public RegisterInfoInterface + public lldb_private::RegisterInfoInterface { public: RegisterContextFreeBSD_mips64(const lldb_private::ArchSpec &target_arch); - virtual ~RegisterContextFreeBSD_mips64(); size_t - GetGPRSize(); + GetGPRSize() const override; const lldb_private::RegisterInfo * - GetRegisterInfo(); + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; }; #endif diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp index 2162aaf..257de71 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp @@ -67,10 +67,17 @@ struct dbreg { #include "RegisterInfos_x86_64.h" #undef DECLARE_REGISTER_INFOS_X86_64_STRUCT +static std::vector<lldb_private::RegisterInfo>& +GetSharedRegisterInfoVector () +{ + static std::vector<lldb_private::RegisterInfo> register_infos; + return register_infos; +} + static const RegisterInfo * GetRegisterInfo_i386(const lldb_private::ArchSpec& arch) { - static std::vector<lldb_private::RegisterInfo> g_register_infos; + static std::vector<lldb_private::RegisterInfo> g_register_infos (GetSharedRegisterInfoVector ()); // Allocate RegisterInfo only once if (g_register_infos.empty()) @@ -92,35 +99,61 @@ GetRegisterInfo_i386(const lldb_private::ArchSpec& arch) return &g_register_infos[0]; } -RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) : - RegisterInfoInterface(target_arch) +static const RegisterInfo * +PrivateGetRegisterInfoPtr (const lldb_private::ArchSpec& target_arch) { + switch (target_arch.GetMachine()) + { + case llvm::Triple::x86: + return GetRegisterInfo_i386 (target_arch); + case llvm::Triple::x86_64: + return g_register_infos_x86_64; + default: + assert(false && "Unhandled target architecture."); + return nullptr; + } } -RegisterContextFreeBSD_x86_64::~RegisterContextFreeBSD_x86_64() +static uint32_t +PrivateGetRegisterCount (const lldb_private::ArchSpec& target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::x86: + // This vector should have already been filled. + assert (!GetSharedRegisterInfoVector ().empty () && "i386 register info vector not filled."); + return static_cast<uint32_t> (GetSharedRegisterInfoVector().size ()); + case llvm::Triple::x86_64: + return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) : + lldb_private::RegisterInfoInterface(target_arch), + m_register_info_p (PrivateGetRegisterInfoPtr (target_arch)), + m_register_count (PrivateGetRegisterCount (target_arch)) { } size_t -RegisterContextFreeBSD_x86_64::GetGPRSize() +RegisterContextFreeBSD_x86_64::GetGPRSize() const { return sizeof(GPR); } const RegisterInfo * -RegisterContextFreeBSD_x86_64::GetRegisterInfo() +RegisterContextFreeBSD_x86_64::GetRegisterInfo() const { - switch (m_target_arch.GetCore()) - { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - return GetRegisterInfo_i386 (m_target_arch); - case ArchSpec::eCore_x86_64_x86_64: - return g_register_infos_x86_64; - default: - assert(false && "Unhandled target architecture."); - return NULL; - } + return m_register_info_p; +} + +uint32_t +RegisterContextFreeBSD_x86_64::GetRegisterCount () const +{ + return m_register_count; } + diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h index 731bb0e..21fbdb4 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h @@ -13,17 +13,23 @@ #include "RegisterContextPOSIX.h" class RegisterContextFreeBSD_x86_64: - public RegisterInfoInterface + public lldb_private::RegisterInfoInterface { public: RegisterContextFreeBSD_x86_64(const lldb_private::ArchSpec &target_arch); - virtual ~RegisterContextFreeBSD_x86_64(); size_t - GetGPRSize(); + GetGPRSize() const override; const lldb_private::RegisterInfo * - GetRegisterInfo(); + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + const uint32_t m_register_count; }; #endif diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp index b7adb20..3c37010 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp @@ -130,7 +130,7 @@ RegisterContextHistory::WriteAllRegisterValues (const lldb::DataBufferSP &data_s } uint32_t -RegisterContextHistory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextHistory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC) return 0; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h index 58e1608..04842c6 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h @@ -60,7 +60,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); private: //------------------------------------------------------------------ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index f209d53..b58e6bb 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -163,15 +163,17 @@ RegisterContextLLDB::InitializeZerothFrame() UnwindLogMsg ("using architectural default unwind method"); } - // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us. + // We require either a symbol or function in the symbols context to be successfully + // filled in or this context is of no use to us. + const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; if (pc_module_sp.get() - && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, resolve_scope, m_sym_ctx) & resolve_scope)) { m_sym_ctx_valid = true; } AddressRange addr_range; - m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range); + m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range); if (IsTrapHandlerSymbol (process, m_sym_ctx)) { @@ -216,7 +218,7 @@ RegisterContextLLDB::InitializeZerothFrame() UnwindPlan::RowSP active_row; int cfa_offset = 0; - int row_register_kind = -1; + lldb::RegisterKind row_register_kind = eRegisterKindGeneric; if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc)) { active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); @@ -362,7 +364,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() m_current_offset = -1; m_current_offset_backed_up_one = -1; addr_t cfa_regval = LLDB_INVALID_ADDRESS; - int row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); + RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0); if (row.get()) { @@ -417,18 +419,20 @@ RegisterContextLLDB::InitializeNonZerothFrame() // a function/symbol because it is beyond the bounds of the correct // function and there's no symbol there. ResolveSymbolContextForAddress // will fail to find a symbol, back up the pc by 1 and re-search. + const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, - eSymbolContextFunction | eSymbolContextSymbol, + resolve_scope, m_sym_ctx, resolve_tail_call_address); - // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us. - if ((resolved_scope & eSymbolContextSymbol) == eSymbolContextSymbol) + // We require either a symbol or function in the symbols context to be successfully + // filled in or this context is of no use to us. + if (resolve_scope & resolved_scope) { m_sym_ctx_valid = true; } AddressRange addr_range; - if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) + if (!m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range)) { m_sym_ctx_valid = false; } @@ -461,13 +465,12 @@ RegisterContextLLDB::InitializeNonZerothFrame() temporary_pc.SetOffset(m_current_pc.GetOffset() - 1); m_sym_ctx.Clear(false); m_sym_ctx_valid = false; - if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; + + if (pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope) { - m_sym_ctx_valid = true; - } - if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) - { - m_sym_ctx_valid = false; + if (m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range)) + m_sym_ctx_valid = true; } } @@ -510,7 +513,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() UnwindPlan::RowSP active_row; int cfa_offset = 0; - int row_register_kind = -1; + RegisterKind row_register_kind = eRegisterKindGeneric; // Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get // (e.g. if we have to parse the entire eh_frame section of an ObjectFile for the first time.) @@ -591,7 +594,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() repeating_frames = true; } } - if (repeating_frames && abi->FunctionCallsChangeCFA()) + if (repeating_frames && abi && abi->FunctionCallsChangeCFA()) { UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping"); m_frame_type = eNotAValidFrame; @@ -707,7 +710,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // Note, if we have a symbol context & a symbol, we don't want to follow this code path. This is // for jumping to memory regions without any information available. - if ((!m_sym_ctx_valid || m_sym_ctx.symbol == NULL) && behaves_like_zeroth_frame && m_current_pc.IsValid()) + if ((!m_sym_ctx_valid || (m_sym_ctx.function == NULL && m_sym_ctx.symbol == NULL)) && behaves_like_zeroth_frame && m_current_pc.IsValid()) { uint32_t permissions; addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()); @@ -791,7 +794,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions if (behaves_like_zeroth_frame) { - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one); if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) { if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) @@ -819,8 +822,8 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible. - unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); - if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one); + if (unwind_plan_sp && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) { // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably // don't have any eh_frame instructions available. @@ -889,7 +892,7 @@ RegisterContextLLDB::GetRegisterSet (size_t reg_set) } uint32_t -RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num); } @@ -1415,7 +1418,7 @@ RegisterContextLLDB::TryFallbackUnwindPlan () // where frame 0 (the "next" frame) saved that and retrieve the value. bool -RegisterContextLLDB::ReadGPRValue (int register_kind, uint32_t regnum, addr_t &value) +RegisterContextLLDB::ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, addr_t &value) { if (!IsValid()) return false; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h index 0a60bfe..d6ecfeb 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -67,7 +67,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); bool IsValid () const; @@ -178,7 +178,7 @@ private: // Get the contents of a general purpose (address-size) register for this frame // (usually retrieved from the next frame) bool - ReadGPRValue (int register_kind, uint32_t regnum, lldb::addr_t &value); + ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, lldb::addr_t &value); lldb::UnwindPlanSP GetFastUnwindPlanForFrame (); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp new file mode 100644 index 0000000..8c23e39 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp @@ -0,0 +1,89 @@ +//===-- RegisterContextLinux_arm64.cpp -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include <stddef.h> +#include <vector> +#include <cassert> + +#include "llvm/Support/Compiler.h" +#include "lldb/lldb-defines.h" + +#include "RegisterContextLinux_arm64.h" + +// Based on RegisterContextDarwin_arm64.cpp +#define GPR_OFFSET(idx) ((idx) * 8) +#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::GPR, reg)) + +#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextLinux_arm64::GPR)) +#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::FPU, reg)) + +#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::EXC, reg) + sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU)) +#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::DBG, reg) + sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU) + sizeof (RegisterContextLinux_arm64::EXC)) + +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define REG_CONTEXT_SIZE (sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU) + sizeof (RegisterContextLinux_arm64::EXC)) + + +//----------------------------------------------------------------------------- +// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. +//----------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_ARM64_STRUCT +#include "RegisterInfos_arm64.h" +#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT + +static const lldb_private::RegisterInfo * +GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + return g_register_infos_arm64; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } +} + +static uint32_t +GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + return static_cast<uint32_t>(sizeof(g_register_infos_arm64) / sizeof(g_register_infos_arm64[0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextLinux_arm64::RegisterContextLinux_arm64(const lldb_private::ArchSpec &target_arch) : + lldb_private::RegisterInfoInterface(target_arch), + m_register_info_p(GetRegisterInfoPtr(target_arch)), + m_register_info_count(GetRegisterInfoCount(target_arch)) +{ +} + +size_t +RegisterContextLinux_arm64::GetGPRSize() const +{ + return sizeof(struct RegisterContextLinux_arm64::GPR); +} + +const lldb_private::RegisterInfo * +RegisterContextLinux_arm64::GetRegisterInfo() const +{ + return m_register_info_p; +} + +uint32_t +RegisterContextLinux_arm64::GetRegisterCount() const +{ + return m_register_info_count; +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h new file mode 100644 index 0000000..a9a5a09 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h @@ -0,0 +1,81 @@ +//===-- RegisterContextLinux_arm64.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextLinux_arm64_H_ +#define liblldb_RegisterContextLinux_arm64_H_ + +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" +#include "RegisterContextPOSIX.h" +#include "RegisterInfoInterface.h" + +class RegisterContextLinux_arm64 + : public lldb_private::RegisterInfoInterface +{ +public: + // based on RegisterContextDarwin_arm64.h + struct GPR + { + uint64_t x[29]; // x0-x28 + uint64_t fp; // x29 + uint64_t lr; // x30 + uint64_t sp; // x31 + uint64_t pc; // pc + uint32_t cpsr; // cpsr + }; + + // based on RegisterContextDarwin_arm64.h + struct VReg + { + uint8_t bytes[16]; + }; + + // based on RegisterContextDarwin_arm64.h + struct FPU + { + VReg v[32]; + uint32_t fpsr; + uint32_t fpcr; + }; + + // based on RegisterContextDarwin_arm64.h + struct EXC + { + uint64_t far; // Virtual Fault Address + uint32_t esr; // Exception syndrome + uint32_t exception; // number of arm exception token + }; + + // based on RegisterContextDarwin_arm64.h + struct DBG + { + uint64_t bvr[16]; + uint64_t bcr[16]; + uint64_t wvr[16]; + uint64_t wcr[16]; + uint64_t mdscr_el1; + }; + + RegisterContextLinux_arm64(const lldb_private::ArchSpec &target_arch); + + size_t + GetGPRSize() const override; + + const lldb_private::RegisterInfo * + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + uint32_t m_register_info_count; +}; + +#endif diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp index 0828efb..b9b9dca 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_i386.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp @@ -34,11 +34,39 @@ struct GPR uint32_t ss; }; +struct FPR_i386 +{ + uint16_t fctrl; // FPU Control Word (fcw) + uint16_t fstat; // FPU Status Word (fsw) + uint16_t ftag; // FPU Tag Word (ftw) + uint16_t fop; // Last Instruction Opcode (fop) + union + { + struct + { + uint64_t fip; // Instruction Pointer + uint64_t fdp; // Data Pointer + } x86_64; + struct + { + uint32_t fioff; // FPU IP Offset (fip) + uint32_t fiseg; // FPU IP Selector (fcs) + uint32_t fooff; // FPU Operand Pointer Offset (foo) + uint32_t foseg; // FPU Operand Pointer Selector (fos) + } i386_;// Added _ in the end to avoid error with gcc defining i386 in some cases + } ptr; + uint32_t mxcsr; // MXCSR Register State + uint32_t mxcsrmask; // MXCSR Mask + MMSReg stmm[8]; // 8*16 bytes for each FP-reg = 128 bytes + XMMReg xmm[8]; // 8*16 bytes for each XMM-reg = 128 bytes + uint32_t padding[56]; +}; + struct UserArea { GPR regs; // General purpose registers. int32_t fpvalid; // True if FPU is being used. - FXSAVE i387; // FPU registers. + FPR_i386 i387; // FPU registers. uint32_t tsize; // Text segment size. uint32_t dsize; // Data segment size. uint32_t ssize; // Stack segment size. @@ -54,9 +82,11 @@ struct UserArea uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7). }; -#define DR_SIZE sizeof(UserArea::u_debugreg[0]) +#define DR_SIZE sizeof(((UserArea*)NULL)->u_debugreg[0]) +#define DR_0_OFFSET 0xFC #define DR_OFFSET(reg_index) \ - (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index])) + (DR_0_OFFSET + (reg_index * 4)) +#define FPR_SIZE(reg) sizeof(((FPR_i386*)NULL)->reg) //--------------------------------------------------------------------------- // Include RegisterInfos_i386 to declare our g_register_infos_i386 structure. @@ -70,27 +100,28 @@ RegisterContextLinux_i386::RegisterContextLinux_i386(const ArchSpec &target_arch { } -RegisterContextLinux_i386::~RegisterContextLinux_i386() -{ -} - size_t -RegisterContextLinux_i386::GetGPRSize() +RegisterContextLinux_i386::GetGPRSize() const { return sizeof(GPR); } const RegisterInfo * -RegisterContextLinux_i386::GetRegisterInfo() +RegisterContextLinux_i386::GetRegisterInfo() const { - switch (m_target_arch.GetCore()) + switch (m_target_arch.GetMachine()) { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: + case llvm::Triple::x86: return g_register_infos_i386; default: assert(false && "Unhandled target architecture."); return NULL; } } + +uint32_t +RegisterContextLinux_i386::GetRegisterCount () const +{ + return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0])); +} + diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_i386.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h index 81afdbf..f8b21fc 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_i386.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h @@ -13,17 +13,19 @@ #include "RegisterContextPOSIX.h" class RegisterContextLinux_i386 - : public RegisterInfoInterface + : public lldb_private::RegisterInfoInterface { public: RegisterContextLinux_i386(const lldb_private::ArchSpec &target_arch); - virtual ~RegisterContextLinux_i386(); size_t - GetGPRSize(); + GetGPRSize() const override; const lldb_private::RegisterInfo * - GetRegisterInfo(); + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; }; #endif diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp index 5434ddf..74f016b 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp @@ -69,7 +69,7 @@ struct UserArea uint64_t fault_address; // Control register CR3. }; -#define DR_SIZE sizeof(UserArea::u_debugreg[0]) +#define DR_SIZE sizeof(((UserArea*)NULL)->u_debugreg[0]) #define DR_OFFSET(reg_index) \ (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index])) @@ -80,10 +80,17 @@ struct UserArea #include "RegisterInfos_x86_64.h" #undef DECLARE_REGISTER_INFOS_X86_64_STRUCT +static std::vector<lldb_private::RegisterInfo>& +GetPrivateRegisterInfoVector () +{ + static std::vector<lldb_private::RegisterInfo> g_register_infos; + return g_register_infos; +} + static const RegisterInfo * GetRegisterInfo_i386(const lldb_private::ArchSpec &arch) { - static std::vector<lldb_private::RegisterInfo> g_register_infos; + std::vector<lldb_private::RegisterInfo> &g_register_infos = GetPrivateRegisterInfoVector (); // Allocate RegisterInfo only once if (g_register_infos.empty()) @@ -105,35 +112,60 @@ GetRegisterInfo_i386(const lldb_private::ArchSpec &arch) return &g_register_infos[0]; } -RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) : - RegisterInfoInterface(target_arch) +static const RegisterInfo * +GetRegisterInfoPtr (const ArchSpec &target_arch) { + switch (target_arch.GetMachine()) + { + case llvm::Triple::x86: + return GetRegisterInfo_i386 (target_arch); + case llvm::Triple::x86_64: + return g_register_infos_x86_64; + default: + assert(false && "Unhandled target architecture."); + return nullptr; + } } -RegisterContextLinux_x86_64::~RegisterContextLinux_x86_64() +static uint32_t +GetRegisterInfoCount (const ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::x86: + { + assert (!GetPrivateRegisterInfoVector ().empty () && "i386 register info not yet filled."); + return static_cast<uint32_t> (GetPrivateRegisterInfoVector ().size ()); + } + case llvm::Triple::x86_64: + return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) : + lldb_private::RegisterInfoInterface(target_arch), + m_register_info_p (GetRegisterInfoPtr (target_arch)), + m_register_info_count (GetRegisterInfoCount (target_arch)) { } size_t -RegisterContextLinux_x86_64::GetGPRSize() +RegisterContextLinux_x86_64::GetGPRSize() const { return sizeof(GPR); } const RegisterInfo * -RegisterContextLinux_x86_64::GetRegisterInfo() +RegisterContextLinux_x86_64::GetRegisterInfo() const { - switch (m_target_arch.GetCore()) - { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - return GetRegisterInfo_i386 (m_target_arch); - case ArchSpec::eCore_x86_64_x86_64: - return g_register_infos_x86_64; - default: - assert(false && "Unhandled target architecture."); - return NULL; - } + return m_register_info_p; } +uint32_t +RegisterContextLinux_x86_64::GetRegisterCount () const +{ + return m_register_info_count; +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h index 21c809b..7b68286 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h @@ -13,17 +13,23 @@ #include "RegisterContextPOSIX.h" class RegisterContextLinux_x86_64 - : public RegisterInfoInterface + : public lldb_private::RegisterInfoInterface { public: RegisterContextLinux_x86_64(const lldb_private::ArchSpec &target_arch); - virtual ~RegisterContextLinux_x86_64(); size_t - GetGPRSize(); + GetGPRSize() const override; const lldb_private::RegisterInfo * - GetRegisterInfo(); + GetRegisterInfo() const override; + + uint32_t + GetRegisterCount () const override; + +private: + const lldb_private::RegisterInfo *m_register_info_p; + uint32_t m_register_info_count; }; #endif diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp index 5b6d9fe..e246e71 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp @@ -149,7 +149,7 @@ RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info, // TOOD: need a better way to detect when "long double" types are // the same bytes size as "double" -#if !defined(__arm__) && !defined(_MSC_VER) && !defined(__mips__) +#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) && !defined(_MSC_VER) && !defined(__mips__) case sizeof (long double): if (sizeof (long double) == sizeof(uint32_t)) { @@ -199,7 +199,7 @@ RegisterContextMacOSXFrameBackchain::WriteAllRegisterValues (const lldb::DataBuf uint32_t -RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h index 449e053..505b8d4 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h @@ -63,7 +63,7 @@ public: WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); private: UnwindMacOSXFrameBackchain::Cursor m_cursor; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp index 8c33a68..40d00b1 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp @@ -98,7 +98,7 @@ RegisterContextMemory::GetRegisterSet (size_t reg_set) } uint32_t -RegisterContextMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextMemory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { return m_reg_infos.ConvertRegisterKindToRegisterNumber (kind, num); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h index 8bba52c..9d97dfa 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h @@ -55,7 +55,7 @@ public: GetRegisterSet (size_t reg_set); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); //------------------------------------------------------------------ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX.h index 600dae7..6ddd9cf 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX.h @@ -15,6 +15,7 @@ // Other libraries and framework includes #include "lldb/Core/ArchSpec.h" #include "lldb/Target/RegisterContext.h" +#include "RegisterInfoInterface.h" //------------------------------------------------------------------------------ /// @class POSIXBreakpointProtocol @@ -74,25 +75,5 @@ protected: bool m_watchpoints_initialized; }; -//------------------------------------------------------------------------------ -/// @class RegisterInfoInterface -/// -/// @brief RegisterInfo interface to patch RegisterInfo structure for archs. -class RegisterInfoInterface -{ -public: - RegisterInfoInterface(const lldb_private::ArchSpec& target_arch) : m_target_arch(target_arch) {} - virtual ~RegisterInfoInterface () {} - - virtual size_t - GetGPRSize () = 0; - - virtual const lldb_private::RegisterInfo * - GetRegisterInfo () = 0; - -public: - lldb_private::ArchSpec m_target_arch; -}; - #endif // #ifndef liblldb_RegisterContextPOSIX_H_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp new file mode 100644 index 0000000..ea54a9a --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -0,0 +1,299 @@ +//===-- RegisterContextPOSIX_arm64.cpp --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <cstring> +#include <errno.h> +#include <stdint.h> + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Host/Endian.h" +#include "llvm/Support/Compiler.h" + +#include "RegisterContextPOSIX_arm64.h" +#include "Plugins/Process/elf-core/ProcessElfCore.h" + +// ARM64 general purpose registers. +const uint32_t g_gpr_regnums_arm64[] = +{ + gpr_x0_arm64, + gpr_x1_arm64, + gpr_x2_arm64, + gpr_x3_arm64, + gpr_x4_arm64, + gpr_x5_arm64, + gpr_x6_arm64, + gpr_x7_arm64, + gpr_x8_arm64, + gpr_x9_arm64, + gpr_x10_arm64, + gpr_x11_arm64, + gpr_x12_arm64, + gpr_x13_arm64, + gpr_x14_arm64, + gpr_x15_arm64, + gpr_x16_arm64, + gpr_x17_arm64, + gpr_x18_arm64, + gpr_x19_arm64, + gpr_x20_arm64, + gpr_x21_arm64, + gpr_x22_arm64, + gpr_x23_arm64, + gpr_x24_arm64, + gpr_x25_arm64, + gpr_x26_arm64, + gpr_x27_arm64, + gpr_x28_arm64, + gpr_fp_arm64, + gpr_lr_arm64, + gpr_sp_arm64, + gpr_pc_arm64, + gpr_cpsr_arm64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \ + "g_gpr_regnums_arm64 has wrong number of register infos"); + +// ARM64 floating point registers. +static const uint32_t g_fpu_regnums_arm64[] = +{ + fpu_v0_arm64, + fpu_v1_arm64, + fpu_v2_arm64, + fpu_v3_arm64, + fpu_v4_arm64, + fpu_v5_arm64, + fpu_v6_arm64, + fpu_v7_arm64, + fpu_v8_arm64, + fpu_v9_arm64, + fpu_v10_arm64, + fpu_v11_arm64, + fpu_v12_arm64, + fpu_v13_arm64, + fpu_v14_arm64, + fpu_v15_arm64, + fpu_v16_arm64, + fpu_v17_arm64, + fpu_v18_arm64, + fpu_v19_arm64, + fpu_v20_arm64, + fpu_v21_arm64, + fpu_v22_arm64, + fpu_v23_arm64, + fpu_v24_arm64, + fpu_v25_arm64, + fpu_v26_arm64, + fpu_v27_arm64, + fpu_v28_arm64, + fpu_v29_arm64, + fpu_v30_arm64, + fpu_v31_arm64, + fpu_fpsr_arm64, + fpu_fpcr_arm64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \ + "g_fpu_regnums_arm64 has wrong number of register infos"); + +// Number of register sets provided by this context. +enum +{ + k_num_register_sets = 2 +}; + +// Register sets for ARM64. +static const lldb_private::RegisterSet +g_reg_sets_arm64[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 } +}; + +bool RegisterContextPOSIX_arm64::IsGPR(unsigned reg) +{ + return reg <= m_reg_info.last_gpr; // GPR's come first. +} + +bool RegisterContextPOSIX_arm64::IsFPR(unsigned reg) +{ + return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); +} + +RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : lldb_private::RegisterContext(thread, concrete_frame_idx) +{ + m_register_info_ap.reset(register_info); + + switch (register_info->m_target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + m_reg_info.num_registers = k_num_registers_arm64; + m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64; + m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64; + m_reg_info.last_gpr = k_last_gpr_arm64; + m_reg_info.first_fpr = k_first_fpr_arm64; + m_reg_info.last_fpr = k_last_fpr_arm64; + m_reg_info.first_fpr_v = fpu_v0_arm64; + m_reg_info.last_fpr_v = fpu_v31_arm64; + m_reg_info.gpr_flags = gpr_cpsr_arm64; + break; + default: + assert(false && "Unhandled target architecture."); + break; + } + + ::memset(&m_fpr, 0, sizeof m_fpr); + + // elf-core yet to support ReadFPR() + lldb::ProcessSP base = CalculateProcess(); + if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) + return; +} + +RegisterContextPOSIX_arm64::~RegisterContextPOSIX_arm64() +{ +} + +void +RegisterContextPOSIX_arm64::Invalidate() +{ +} + +void +RegisterContextPOSIX_arm64::InvalidateAllRegisters() +{ +} + +unsigned +RegisterContextPOSIX_arm64::GetRegisterOffset(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_offset; +} + +unsigned +RegisterContextPOSIX_arm64::GetRegisterSize(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_size; +} + +size_t +RegisterContextPOSIX_arm64::GetRegisterCount() +{ + size_t num_registers = m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers; + return num_registers; +} + +size_t +RegisterContextPOSIX_arm64::GetGPRSize() +{ + return m_register_info_ap->GetGPRSize (); +} + +const lldb_private::RegisterInfo * +RegisterContextPOSIX_arm64::GetRegisterInfo() +{ + // Commonly, this method is overridden and g_register_infos is copied and specialized. + // So, use GetRegisterInfo() rather than g_register_infos in this scope. + return m_register_info_ap->GetRegisterInfo (); +} + +const lldb_private::RegisterInfo * +RegisterContextPOSIX_arm64::GetRegisterInfoAtIndex(size_t reg) +{ + if (reg < m_reg_info.num_registers) + return &GetRegisterInfo()[reg]; + else + return NULL; +} + +size_t +RegisterContextPOSIX_arm64::GetRegisterSetCount() +{ + size_t sets = 0; + for (size_t set = 0; set < k_num_register_sets; ++set) + { + if (IsRegisterSetAvailable(set)) + ++sets; + } + + return sets; +} + +const lldb_private::RegisterSet * +RegisterContextPOSIX_arm64::GetRegisterSet(size_t set) +{ + if (IsRegisterSetAvailable(set)) + { + switch (m_register_info_ap->m_target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + return &g_reg_sets_arm64[set]; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } + } + return NULL; +} + +const char * +RegisterContextPOSIX_arm64::GetRegisterName(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register offset."); + return GetRegisterInfo()[reg].name; +} + +lldb::ByteOrder +RegisterContextPOSIX_arm64::GetByteOrder() +{ + // Get the target process whose privileged thread was used for the register read. + lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; + lldb_private::Process *process = CalculateProcess().get(); + + if (process) + byte_order = process->GetByteOrder(); + return byte_order; +} + +bool +RegisterContextPOSIX_arm64::IsRegisterSetAvailable(size_t set_index) +{ + return set_index < k_num_register_sets; +} + + +// Used when parsing DWARF and EH frame information and any other +// object file sections that contain register numbers in them. +uint32_t +RegisterContextPOSIX_arm64::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) +{ + const uint32_t num_regs = GetRegisterCount(); + + assert (kind < lldb::kNumRegisterKinds); + for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) + { + const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx); + + if (reg_info->kinds[kind] == num) + return reg_idx; + } + + return LLDB_INVALID_REGNUM; +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h new file mode 100644 index 0000000..3639960 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h @@ -0,0 +1,272 @@ +//===-- RegisterContextPOSIX_arm64.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIX_arm64_H_ +#define liblldb_RegisterContextPOSIX_arm64_H_ + +#include "lldb/Core/Log.h" +#include "RegisterContextPOSIX.h" + +class ProcessMonitor; + +//--------------------------------------------------------------------------- +// Internal codes for all ARM64 registers. +//--------------------------------------------------------------------------- +enum +{ + k_first_gpr_arm64, + gpr_x0_arm64 = k_first_gpr_arm64, + gpr_x1_arm64, + gpr_x2_arm64, + gpr_x3_arm64, + gpr_x4_arm64, + gpr_x5_arm64, + gpr_x6_arm64, + gpr_x7_arm64, + gpr_x8_arm64, + gpr_x9_arm64, + gpr_x10_arm64, + gpr_x11_arm64, + gpr_x12_arm64, + gpr_x13_arm64, + gpr_x14_arm64, + gpr_x15_arm64, + gpr_x16_arm64, + gpr_x17_arm64, + gpr_x18_arm64, + gpr_x19_arm64, + gpr_x20_arm64, + gpr_x21_arm64, + gpr_x22_arm64, + gpr_x23_arm64, + gpr_x24_arm64, + gpr_x25_arm64, + gpr_x26_arm64, + gpr_x27_arm64, + gpr_x28_arm64, + gpr_fp_arm64, + gpr_lr_arm64, + gpr_sp_arm64, + gpr_pc_arm64, + gpr_cpsr_arm64, + + k_last_gpr_arm64 = gpr_cpsr_arm64, + + k_first_fpr_arm64, + fpu_v0_arm64 = k_first_fpr_arm64, + fpu_v1_arm64, + fpu_v2_arm64, + fpu_v3_arm64, + fpu_v4_arm64, + fpu_v5_arm64, + fpu_v6_arm64, + fpu_v7_arm64, + fpu_v8_arm64, + fpu_v9_arm64, + fpu_v10_arm64, + fpu_v11_arm64, + fpu_v12_arm64, + fpu_v13_arm64, + fpu_v14_arm64, + fpu_v15_arm64, + fpu_v16_arm64, + fpu_v17_arm64, + fpu_v18_arm64, + fpu_v19_arm64, + fpu_v20_arm64, + fpu_v21_arm64, + fpu_v22_arm64, + fpu_v23_arm64, + fpu_v24_arm64, + fpu_v25_arm64, + fpu_v26_arm64, + fpu_v27_arm64, + fpu_v28_arm64, + fpu_v29_arm64, + fpu_v30_arm64, + fpu_v31_arm64, + fpu_fpsr_arm64, + fpu_fpcr_arm64, + k_last_fpr_arm64 = fpu_fpcr_arm64, + + exc_far_arm64, + exc_esr_arm64, + exc_exception_arm64, + + dbg_bvr0_arm64, + dbg_bvr1_arm64, + dbg_bvr2_arm64, + dbg_bvr3_arm64, + dbg_bvr4_arm64, + dbg_bvr5_arm64, + dbg_bvr6_arm64, + dbg_bvr7_arm64, + dbg_bvr8_arm64, + dbg_bvr9_arm64, + dbg_bvr10_arm64, + dbg_bvr11_arm64, + dbg_bvr12_arm64, + dbg_bvr13_arm64, + dbg_bvr14_arm64, + dbg_bvr15_arm64, + dbg_bcr0_arm64, + dbg_bcr1_arm64, + dbg_bcr2_arm64, + dbg_bcr3_arm64, + dbg_bcr4_arm64, + dbg_bcr5_arm64, + dbg_bcr6_arm64, + dbg_bcr7_arm64, + dbg_bcr8_arm64, + dbg_bcr9_arm64, + dbg_bcr10_arm64, + dbg_bcr11_arm64, + dbg_bcr12_arm64, + dbg_bcr13_arm64, + dbg_bcr14_arm64, + dbg_bcr15_arm64, + dbg_wvr0_arm64, + dbg_wvr1_arm64, + dbg_wvr2_arm64, + dbg_wvr3_arm64, + dbg_wvr4_arm64, + dbg_wvr5_arm64, + dbg_wvr6_arm64, + dbg_wvr7_arm64, + dbg_wvr8_arm64, + dbg_wvr9_arm64, + dbg_wvr10_arm64, + dbg_wvr11_arm64, + dbg_wvr12_arm64, + dbg_wvr13_arm64, + dbg_wvr14_arm64, + dbg_wvr15_arm64, + dbg_wcr0_arm64, + dbg_wcr1_arm64, + dbg_wcr2_arm64, + dbg_wcr3_arm64, + dbg_wcr4_arm64, + dbg_wcr5_arm64, + dbg_wcr6_arm64, + dbg_wcr7_arm64, + dbg_wcr8_arm64, + dbg_wcr9_arm64, + dbg_wcr10_arm64, + dbg_wcr11_arm64, + dbg_wcr12_arm64, + dbg_wcr13_arm64, + dbg_wcr14_arm64, + dbg_wcr15_arm64, + + k_num_registers_arm64, + k_num_gpr_registers_arm64 = k_last_gpr_arm64 - k_first_gpr_arm64 + 1, + k_num_fpr_registers_arm64 = k_last_fpr_arm64 - k_first_fpr_arm64 + 1 +}; + +class RegisterContextPOSIX_arm64 + : public lldb_private::RegisterContext +{ +public: + RegisterContextPOSIX_arm64 (lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + + ~RegisterContextPOSIX_arm64(); + + void + Invalidate(); + + void + InvalidateAllRegisters(); + + size_t + GetRegisterCount(); + + virtual size_t + GetGPRSize(); + + virtual unsigned + GetRegisterSize(unsigned reg); + + virtual unsigned + GetRegisterOffset(unsigned reg); + + const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex(size_t reg); + + size_t + GetRegisterSetCount(); + + const lldb_private::RegisterSet * + GetRegisterSet(size_t set); + + const char * + GetRegisterName(unsigned reg); + + uint32_t + ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num); + +protected: + struct RegInfo + { + uint32_t num_registers; + uint32_t num_gpr_registers; + uint32_t num_fpr_registers; + + uint32_t last_gpr; + uint32_t first_fpr; + uint32_t last_fpr; + + uint32_t first_fpr_v; + uint32_t last_fpr_v; + + uint32_t gpr_flags; + }; + + // based on RegisterContextDarwin_arm64.h + struct VReg + { + uint8_t bytes[16]; + }; + + // based on RegisterContextDarwin_arm64.h + struct FPU + { + VReg v[32]; + uint32_t fpsr; + uint32_t fpcr; + }; + + uint64_t m_gpr_arm64[k_num_gpr_registers_arm64]; // 64-bit general purpose registers. + RegInfo m_reg_info; + struct RegisterContextPOSIX_arm64::FPU m_fpr; // floating-point registers including extended register sets. + std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) + + // Determines if an extended register set is supported on the processor running the inferior process. + virtual bool + IsRegisterSetAvailable(size_t set_index); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfo(); + + bool + IsGPR(unsigned reg); + + bool + IsFPR(unsigned reg); + + lldb::ByteOrder GetByteOrder(); + + virtual bool ReadGPR() = 0; + virtual bool ReadFPR() = 0; + virtual bool WriteGPR() = 0; + virtual bool WriteFPR() = 0; +}; + +#endif // #ifndef liblldb_RegisterContextPOSIX_arm64_H_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp index 45c99ae..cefedae 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp @@ -20,7 +20,6 @@ #include "lldb/Host/Endian.h" #include "llvm/Support/Compiler.h" -#include "ProcessPOSIX.h" #include "RegisterContextPOSIX_mips64.h" #include "Plugins/Process/elf-core/ProcessElfCore.h" @@ -219,7 +218,7 @@ RegisterContextPOSIX_mips64::IsRegisterSetAvailable(size_t set_index) // Used when parsing DWARF and EH frame information and any other // object file sections that contain register numbers in them. uint32_t -RegisterContextPOSIX_mips64::ConvertRegisterKindToRegisterNumber(uint32_t kind, +RegisterContextPOSIX_mips64::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num) { const uint32_t num_regs = GetRegisterCount(); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h index a2a7d1f..991179b 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h @@ -73,7 +73,7 @@ class RegisterContextPOSIX_mips64 public: RegisterContextPOSIX_mips64 (lldb_private::Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info); + lldb_private::RegisterInfoInterface *register_info); ~RegisterContextPOSIX_mips64(); @@ -108,11 +108,11 @@ public: GetRegisterName(unsigned reg); uint32_t - ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num); protected: uint64_t m_gpr_mips64[k_num_gpr_registers_mips64]; // general purpose registers. - std::unique_ptr<RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) + std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) // Determines if an extended register set is supported on the processor running the inferior process. virtual bool diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp index 9ae541a..2925a33 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp @@ -20,7 +20,6 @@ #include "lldb/Host/Endian.h" #include "llvm/Support/Compiler.h" -#include "ProcessPOSIX.h" #include "RegisterContext_x86.h" #include "RegisterContextPOSIX_x86.h" #include "Plugins/Process/elf-core/ProcessElfCore.h" @@ -62,9 +61,10 @@ g_gpr_regnums_i386[] = gpr_al_i386, gpr_bl_i386, gpr_cl_i386, - gpr_dl_i386 + gpr_dl_i386, + LLDB_INVALID_REGNUM, // Register sets must be terminated with LLDB_INVALID_REGNUM. }; -static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) == k_num_gpr_registers_i386, +static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - 1 == k_num_gpr_registers_i386, "g_gpr_regnums_i386 has wrong number of register infos"); const uint32_t @@ -103,9 +103,10 @@ g_fpu_regnums_i386[] = fpu_xmm4_i386, fpu_xmm5_i386, fpu_xmm6_i386, - fpu_xmm7_i386 + fpu_xmm7_i386, + LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM. }; -static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) == k_num_fpr_registers_i386, +static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - 1 == k_num_fpr_registers_i386, "g_fpu_regnums_i386 has wrong number of register infos"); const uint32_t @@ -118,9 +119,10 @@ g_avx_regnums_i386[] = fpu_ymm4_i386, fpu_ymm5_i386, fpu_ymm6_i386, - fpu_ymm7_i386 + fpu_ymm7_i386, + LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM. }; -static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) == k_num_avx_registers_i386, +static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 == k_num_avx_registers_i386, " g_avx_regnums_i386 has wrong number of register infos"); static const @@ -202,8 +204,9 @@ uint32_t g_gpr_regnums_x86_64[] = gpr_r13l_x86_64, // Low 8 bits or r13 gpr_r14l_x86_64, // Low 8 bits or r14 gpr_r15l_x86_64, // Low 8 bits or r15 + LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM. }; -static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) == k_num_gpr_registers_x86_64, +static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - 1 == k_num_gpr_registers_x86_64, "g_gpr_regnums_x86_64 has wrong number of register infos"); static const uint32_t @@ -250,9 +253,10 @@ g_fpu_regnums_x86_64[] = fpu_xmm12_x86_64, fpu_xmm13_x86_64, fpu_xmm14_x86_64, - fpu_xmm15_x86_64 + fpu_xmm15_x86_64, + LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM. }; -static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) == k_num_fpr_registers_x86_64, +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"); static const uint32_t @@ -273,9 +277,10 @@ g_avx_regnums_x86_64[] = fpu_ymm12_x86_64, fpu_ymm13_x86_64, fpu_ymm14_x86_64, - fpu_ymm15_x86_64 + fpu_ymm15_x86_64, + LLDB_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM. }; -static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) == k_num_avx_registers_x86_64, +static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - 1 == k_num_avx_registers_x86_64, "g_avx_regnums_x86_64 has wrong number of register infos"); uint32_t RegisterContextPOSIX_x86::g_contained_eax[] = { gpr_eax_i386, LLDB_INVALID_REGNUM }; @@ -384,11 +389,9 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread, { m_register_info_ap.reset(register_info); - switch (register_info->m_target_arch.GetCore()) + switch (register_info->m_target_arch.GetMachine()) { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: + case llvm::Triple::x86: m_reg_info.num_registers = k_num_registers_i386; m_reg_info.num_gpr_registers = k_num_gpr_registers_i386; m_reg_info.num_fpr_registers = k_num_fpr_registers_i386; @@ -407,7 +410,7 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread, m_reg_info.first_dr = dr0_i386; m_reg_info.gpr_flags = gpr_eflags_i386; break; - case ArchSpec::eCore_x86_64_x86_64: + case llvm::Triple::x86_64: m_reg_info.num_registers = k_num_registers_x86_64; m_reg_info.num_gpr_registers = k_num_gpr_registers_x86_64; m_reg_info.num_fpr_registers = k_num_fpr_registers_x86_64; @@ -537,13 +540,11 @@ RegisterContextPOSIX_x86::GetRegisterSet(size_t set) { if (IsRegisterSetAvailable(set)) { - switch (m_register_info_ap->m_target_arch.GetCore()) + switch (m_register_info_ap->m_target_arch.GetMachine()) { - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: + case llvm::Triple::x86: return &g_reg_sets_i386[set]; - case ArchSpec::eCore_x86_64_x86_64: + case llvm::Triple::x86_64: return &g_reg_sets_x86_64[set]; default: assert(false && "Unhandled target architecture."); @@ -647,8 +648,8 @@ RegisterContextPOSIX_x86::IsRegisterSetAvailable(size_t set_index) // Used when parsing DWARF and EH frame information and any other // object file sections that contain register numbers in them. uint32_t -RegisterContextPOSIX_x86::ConvertRegisterKindToRegisterNumber(uint32_t kind, - uint32_t num) +RegisterContextPOSIX_x86::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) { const uint32_t num_regs = GetRegisterCount(); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h index 5e92202..4db7802 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h @@ -296,7 +296,7 @@ class RegisterContextPOSIX_x86 public: RegisterContextPOSIX_x86 (lldb_private::Thread &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info); + lldb_private::RegisterInfoInterface *register_info); ~RegisterContextPOSIX_x86(); @@ -331,7 +331,7 @@ public: GetRegisterName(unsigned reg); uint32_t - ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num); //--------------------------------------------------------------------------- // Note: prefer kernel definitions over user-land @@ -428,7 +428,7 @@ protected: FPR m_fpr; // floating-point registers including extended register sets. IOVEC m_iovec; // wrapper for xsave. YMM m_ymm_set; // copy of ymmh and xmm register halves. - std::unique_ptr<RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) + std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) // Determines if an extended register set is supported on the processor running the inferior process. virtual bool diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp index d35a5d0..46dafa1 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp @@ -167,7 +167,7 @@ RegisterContextThreadMemory::CopyFromRegisterContext (lldb::RegisterContextSP re } uint32_t -RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { UpdateRegisterContext (); if (m_reg_ctx_sp) diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h index 8d7a4b6..161ef04 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h @@ -66,7 +66,7 @@ public: CopyFromRegisterContext (lldb::RegisterContextSP context); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); //------------------------------------------------------------------ // Subclasses can override these functions if desired diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContext_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_mips64.h index dfd473d..dfd473d 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContext_mips64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_mips64.h diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContext_x86.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h index df3e1e5..6b3f6fb 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContext_x86.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h @@ -34,8 +34,16 @@ enum gcc_ecx_i386, gcc_edx_i386, gcc_ebx_i386, - gcc_ebp_i386, // Warning: these are switched from dwarf values - gcc_esp_i386, // + + // on Darwin esp & ebp are reversed in the eh_frame section for i386 (versus dwarf's reg numbering). + // To be specific: + // i386+darwin eh_frame: 4 is ebp, 5 is esp + // i386+everyone else eh_frame: 4 is esp, 5 is ebp + // i386 dwarf: 4 is esp, 5 is ebp + // lldb will get the darwin-specific eh_frame reg numberings from debugserver instead of here so we + // only encode the 4 == esp, 5 == ebp numbers in this generic header. + gcc_esp_i386, + gcc_ebp_i386, gcc_esi_i386, gcc_edi_i386, gcc_eip_i386, @@ -411,7 +419,7 @@ struct FXSAVE uint32_t fiseg; // FPU IP Selector (fcs) uint32_t fooff; // FPU Operand Pointer Offset (foo) uint32_t foseg; // FPU Operand Pointer Selector (fos) - } i386; + } i386_;// Added _ in the end to avoid error with gcc defining i386 in some cases } ptr; uint32_t mxcsr; // MXCSR Register State uint32_t mxcsrmask; // MXCSR Mask diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h new file mode 100644 index 0000000..382475f --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h @@ -0,0 +1,49 @@ +//===-- RegisterInfoInterface.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_RegisterInfoInterface_h +#define lldb_RegisterInfoInterface_h + +#include "lldb/Core/ArchSpec.h" + +namespace lldb_private +{ + + ///------------------------------------------------------------------------------ + /// @class RegisterInfoInterface + /// + /// @brief RegisterInfo interface to patch RegisterInfo structure for archs. + ///------------------------------------------------------------------------------ + class RegisterInfoInterface + { + public: + RegisterInfoInterface(const lldb_private::ArchSpec& target_arch) : m_target_arch(target_arch) {} + virtual ~RegisterInfoInterface () {} + + virtual size_t + GetGPRSize () const = 0; + + virtual const lldb_private::RegisterInfo * + GetRegisterInfo () const = 0; + + virtual uint32_t + GetRegisterCount () const = 0; + + const lldb_private::ArchSpec& + GetTargetArchitecture() const + { return m_target_arch; } + + public: + // FIXME make private. + lldb_private::ArchSpec m_target_arch; + }; + +} + +#endif diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h new file mode 100644 index 0000000..1bb4e89 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h @@ -0,0 +1,347 @@ +//===-- RegisterInfos_arm64.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT + +#include <stddef.h> + +#include "lldb/lldb-private.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" + +#include "ARM64_GCC_Registers.h" +#include "ARM64_DWARF_Registers.h" + +#ifndef GPR_OFFSET +#error GPR_OFFSET must be defined before including this header file +#endif + +#ifndef GPR_OFFSET_NAME +#error GPR_OFFSET_NAME must be defined before including this header file +#endif + +#ifndef FPU_OFFSET +#error FPU_OFFSET must be defined before including this header file +#endif + +#ifndef FPU_OFFSET_NAME +#error FPU_OFFSET_NAME must be defined before including this header file +#endif + +#ifndef EXC_OFFSET_NAME +#error EXC_OFFSET_NAME must be defined before including this header file +#endif + +#ifndef DBG_OFFSET_NAME +#error DBG_OFFSET_NAME must be defined before including this header file +#endif + +#ifndef DEFINE_DBG +#error DEFINE_DBG must be defined before including this header file +#endif + +enum +{ + gpr_x0 = 0, + gpr_x1, + gpr_x2, + gpr_x3, + gpr_x4, + gpr_x5, + gpr_x6, + gpr_x7, + gpr_x8, + gpr_x9, + gpr_x10, + gpr_x11, + gpr_x12, + gpr_x13, + gpr_x14, + gpr_x15, + gpr_x16, + gpr_x17, + gpr_x18, + gpr_x19, + gpr_x20, + gpr_x21, + gpr_x22, + gpr_x23, + gpr_x24, + gpr_x25, + gpr_x26, + gpr_x27, + gpr_x28, + gpr_x29 = 29, gpr_fp = gpr_x29, + gpr_x30 = 30, gpr_lr = gpr_x30, gpr_ra = gpr_x30, + gpr_x31 = 31, gpr_sp = gpr_x31, + gpr_pc = 32, + gpr_cpsr, + + fpu_v0, + fpu_v1, + fpu_v2, + fpu_v3, + fpu_v4, + fpu_v5, + fpu_v6, + fpu_v7, + fpu_v8, + fpu_v9, + fpu_v10, + fpu_v11, + fpu_v12, + fpu_v13, + fpu_v14, + fpu_v15, + fpu_v16, + fpu_v17, + fpu_v18, + fpu_v19, + fpu_v20, + fpu_v21, + fpu_v22, + fpu_v23, + fpu_v24, + fpu_v25, + fpu_v26, + fpu_v27, + fpu_v28, + fpu_v29, + fpu_v30, + fpu_v31, + + fpu_fpsr, + fpu_fpcr, + + exc_far, + exc_esr, + exc_exception, + + dbg_bvr0, + dbg_bvr1, + dbg_bvr2, + dbg_bvr3, + dbg_bvr4, + dbg_bvr5, + dbg_bvr6, + dbg_bvr7, + dbg_bvr8, + dbg_bvr9, + dbg_bvr10, + dbg_bvr11, + dbg_bvr12, + dbg_bvr13, + dbg_bvr14, + dbg_bvr15, + + dbg_bcr0, + dbg_bcr1, + dbg_bcr2, + dbg_bcr3, + dbg_bcr4, + dbg_bcr5, + dbg_bcr6, + dbg_bcr7, + dbg_bcr8, + dbg_bcr9, + dbg_bcr10, + dbg_bcr11, + dbg_bcr12, + dbg_bcr13, + dbg_bcr14, + dbg_bcr15, + + dbg_wvr0, + dbg_wvr1, + dbg_wvr2, + dbg_wvr3, + dbg_wvr4, + dbg_wvr5, + dbg_wvr6, + dbg_wvr7, + dbg_wvr8, + dbg_wvr9, + dbg_wvr10, + dbg_wvr11, + dbg_wvr12, + dbg_wvr13, + dbg_wvr14, + dbg_wvr15, + + dbg_wcr0, + dbg_wcr1, + dbg_wcr2, + dbg_wcr3, + dbg_wcr4, + dbg_wcr5, + dbg_wcr6, + dbg_wcr7, + dbg_wcr8, + dbg_wcr9, + dbg_wcr10, + dbg_wcr11, + dbg_wcr12, + dbg_wcr13, + dbg_wcr14, + dbg_wcr15, + + k_num_registers +}; + +static lldb_private::RegisterInfo g_register_infos_arm64[] = { +// General purpose registers +// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS +// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== =============== +{ "x0", NULL, 8, GPR_OFFSET(0), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x0, arm64_dwarf::x0, LLDB_INVALID_REGNUM, arm64_gcc::x0, gpr_x0 }, NULL, NULL}, +{ "x1", NULL, 8, GPR_OFFSET(1), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x1, arm64_dwarf::x1, LLDB_INVALID_REGNUM, arm64_gcc::x1, gpr_x1 }, NULL, NULL}, +{ "x2", NULL, 8, GPR_OFFSET(2), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x2, arm64_dwarf::x2, LLDB_INVALID_REGNUM, arm64_gcc::x2, gpr_x2 }, NULL, NULL}, +{ "x3", NULL, 8, GPR_OFFSET(3), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x3, arm64_dwarf::x3, LLDB_INVALID_REGNUM, arm64_gcc::x3, gpr_x3 }, NULL, NULL}, +{ "x4", NULL, 8, GPR_OFFSET(4), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x4, arm64_dwarf::x4, LLDB_INVALID_REGNUM, arm64_gcc::x4, gpr_x4 }, NULL, NULL}, +{ "x5", NULL, 8, GPR_OFFSET(5), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x5, arm64_dwarf::x5, LLDB_INVALID_REGNUM, arm64_gcc::x5, gpr_x5 }, NULL, NULL}, +{ "x6", NULL, 8, GPR_OFFSET(6), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x6, arm64_dwarf::x6, LLDB_INVALID_REGNUM, arm64_gcc::x6, gpr_x6 }, NULL, NULL}, +{ "x7", NULL, 8, GPR_OFFSET(7), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x7, arm64_dwarf::x7, LLDB_INVALID_REGNUM, arm64_gcc::x7, gpr_x7 }, NULL, NULL}, +{ "x8", NULL, 8, GPR_OFFSET(8), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x8, arm64_dwarf::x8, LLDB_INVALID_REGNUM, arm64_gcc::x8, gpr_x8 }, NULL, NULL}, +{ "x9", NULL, 8, GPR_OFFSET(9), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x9, arm64_dwarf::x9, LLDB_INVALID_REGNUM, arm64_gcc::x9, gpr_x9 }, NULL, NULL}, +{ "x10", NULL, 8, GPR_OFFSET(10), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x10, arm64_dwarf::x10, LLDB_INVALID_REGNUM, arm64_gcc::x10, gpr_x10 }, NULL, NULL}, +{ "x11", NULL, 8, GPR_OFFSET(11), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x11, arm64_dwarf::x11, LLDB_INVALID_REGNUM, arm64_gcc::x11, gpr_x11 }, NULL, NULL}, +{ "x12", NULL, 8, GPR_OFFSET(12), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x12, arm64_dwarf::x12, LLDB_INVALID_REGNUM, arm64_gcc::x12, gpr_x12 }, NULL, NULL}, +{ "x13", NULL, 8, GPR_OFFSET(13), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x13, arm64_dwarf::x13, LLDB_INVALID_REGNUM, arm64_gcc::x13, gpr_x13 }, NULL, NULL}, +{ "x14", NULL, 8, GPR_OFFSET(14), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x14, arm64_dwarf::x14, LLDB_INVALID_REGNUM, arm64_gcc::x14, gpr_x14 }, NULL, NULL}, +{ "x15", NULL, 8, GPR_OFFSET(15), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x15, arm64_dwarf::x15, LLDB_INVALID_REGNUM, arm64_gcc::x15, gpr_x15 }, NULL, NULL}, +{ "x16", NULL, 8, GPR_OFFSET(16), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x16, arm64_dwarf::x16, LLDB_INVALID_REGNUM, arm64_gcc::x16, gpr_x16 }, NULL, NULL}, +{ "x17", NULL, 8, GPR_OFFSET(17), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x17, arm64_dwarf::x17, LLDB_INVALID_REGNUM, arm64_gcc::x17, gpr_x17 }, NULL, NULL}, +{ "x18", NULL, 8, GPR_OFFSET(18), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x18, arm64_dwarf::x18, LLDB_INVALID_REGNUM, arm64_gcc::x18, gpr_x18 }, NULL, NULL}, +{ "x19", NULL, 8, GPR_OFFSET(19), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x19, arm64_dwarf::x19, LLDB_INVALID_REGNUM, arm64_gcc::x19, gpr_x19 }, NULL, NULL}, +{ "x20", NULL, 8, GPR_OFFSET(20), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x20, arm64_dwarf::x20, LLDB_INVALID_REGNUM, arm64_gcc::x20, gpr_x20 }, NULL, NULL}, +{ "x21", NULL, 8, GPR_OFFSET(21), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x21, arm64_dwarf::x21, LLDB_INVALID_REGNUM, arm64_gcc::x21, gpr_x21 }, NULL, NULL}, +{ "x22", NULL, 8, GPR_OFFSET(22), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x22, arm64_dwarf::x22, LLDB_INVALID_REGNUM, arm64_gcc::x22, gpr_x22 }, NULL, NULL}, +{ "x23", NULL, 8, GPR_OFFSET(23), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x23, arm64_dwarf::x23, LLDB_INVALID_REGNUM, arm64_gcc::x23, gpr_x23 }, NULL, NULL}, +{ "x24", NULL, 8, GPR_OFFSET(24), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x24, arm64_dwarf::x24, LLDB_INVALID_REGNUM, arm64_gcc::x24, gpr_x24 }, NULL, NULL}, +{ "x25", NULL, 8, GPR_OFFSET(25), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x25, arm64_dwarf::x25, LLDB_INVALID_REGNUM, arm64_gcc::x25, gpr_x25 }, NULL, NULL}, +{ "x26", NULL, 8, GPR_OFFSET(26), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x26, arm64_dwarf::x26, LLDB_INVALID_REGNUM, arm64_gcc::x26, gpr_x26 }, NULL, NULL}, +{ "x27", NULL, 8, GPR_OFFSET(27), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x27, arm64_dwarf::x27, LLDB_INVALID_REGNUM, arm64_gcc::x27, gpr_x27 }, NULL, NULL}, +{ "x28", NULL, 8, GPR_OFFSET(28), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x28, arm64_dwarf::x28, LLDB_INVALID_REGNUM, arm64_gcc::x28, gpr_x28 }, NULL, NULL}, + +{ "fp", "x29", 8, GPR_OFFSET(29), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::fp, arm64_dwarf::fp, LLDB_REGNUM_GENERIC_FP, arm64_gcc::fp, gpr_fp }, NULL, NULL}, +{ "lr", "x30", 8, GPR_OFFSET(30), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::lr, arm64_dwarf::lr, LLDB_REGNUM_GENERIC_RA, arm64_gcc::lr, gpr_lr }, NULL, NULL}, +{ "sp", "x31", 8, GPR_OFFSET(31), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::sp, arm64_dwarf::sp, LLDB_REGNUM_GENERIC_SP, arm64_gcc::sp, gpr_sp }, NULL, NULL}, +{ "pc", NULL, 8, GPR_OFFSET(32), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::pc, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, arm64_gcc::pc, gpr_pc }, NULL, NULL}, + +{ "cpsr", NULL, 4, GPR_OFFSET_NAME(cpsr), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::cpsr, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, arm64_gcc::cpsr, gpr_cpsr }, NULL, NULL}, + +{ "v0", NULL, 16, FPU_OFFSET(0), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, arm64_gcc::v0, fpu_v0 }, NULL, NULL}, +{ "v1", NULL, 16, FPU_OFFSET(1), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, arm64_gcc::v1, fpu_v1 }, NULL, NULL}, +{ "v2", NULL, 16, FPU_OFFSET(2), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, arm64_gcc::v2, fpu_v2 }, NULL, NULL}, +{ "v3", NULL, 16, FPU_OFFSET(3), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, arm64_gcc::v3, fpu_v3 }, NULL, NULL}, +{ "v4", NULL, 16, FPU_OFFSET(4), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, arm64_gcc::v4, fpu_v4 }, NULL, NULL}, +{ "v5", NULL, 16, FPU_OFFSET(5), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, arm64_gcc::v5, fpu_v5 }, NULL, NULL}, +{ "v6", NULL, 16, FPU_OFFSET(6), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, arm64_gcc::v6, fpu_v6 }, NULL, NULL}, +{ "v7", NULL, 16, FPU_OFFSET(7), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, arm64_gcc::v7, fpu_v7 }, NULL, NULL}, +{ "v8", NULL, 16, FPU_OFFSET(8), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, arm64_gcc::v8, fpu_v8 }, NULL, NULL}, +{ "v9", NULL, 16, FPU_OFFSET(9), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, arm64_gcc::v9, fpu_v9 }, NULL, NULL}, +{ "v10", NULL, 16, FPU_OFFSET(10), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, arm64_gcc::v10, fpu_v10 }, NULL, NULL}, +{ "v11", NULL, 16, FPU_OFFSET(11), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, arm64_gcc::v11, fpu_v11 }, NULL, NULL}, +{ "v12", NULL, 16, FPU_OFFSET(12), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, arm64_gcc::v12, fpu_v12 }, NULL, NULL}, +{ "v13", NULL, 16, FPU_OFFSET(13), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, arm64_gcc::v13, fpu_v13 }, NULL, NULL}, +{ "v14", NULL, 16, FPU_OFFSET(14), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, arm64_gcc::v14, fpu_v14 }, NULL, NULL}, +{ "v15", NULL, 16, FPU_OFFSET(15), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, arm64_gcc::v15, fpu_v15 }, NULL, NULL}, +{ "v16", NULL, 16, FPU_OFFSET(16), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, arm64_gcc::v16, fpu_v16 }, NULL, NULL}, +{ "v17", NULL, 16, FPU_OFFSET(17), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, arm64_gcc::v17, fpu_v17 }, NULL, NULL}, +{ "v18", NULL, 16, FPU_OFFSET(18), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, arm64_gcc::v18, fpu_v18 }, NULL, NULL}, +{ "v19", NULL, 16, FPU_OFFSET(19), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, arm64_gcc::v19, fpu_v19 }, NULL, NULL}, +{ "v20", NULL, 16, FPU_OFFSET(20), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, arm64_gcc::v20, fpu_v20 }, NULL, NULL}, +{ "v21", NULL, 16, FPU_OFFSET(21), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, arm64_gcc::v21, fpu_v21 }, NULL, NULL}, +{ "v22", NULL, 16, FPU_OFFSET(22), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, arm64_gcc::v22, fpu_v22 }, NULL, NULL}, +{ "v23", NULL, 16, FPU_OFFSET(23), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, arm64_gcc::v23, fpu_v23 }, NULL, NULL}, +{ "v24", NULL, 16, FPU_OFFSET(24), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, arm64_gcc::v24, fpu_v24 }, NULL, NULL}, +{ "v25", NULL, 16, FPU_OFFSET(25), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, arm64_gcc::v25, fpu_v25 }, NULL, NULL}, +{ "v26", NULL, 16, FPU_OFFSET(26), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, arm64_gcc::v26, fpu_v26 }, NULL, NULL}, +{ "v27", NULL, 16, FPU_OFFSET(27), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, arm64_gcc::v27, fpu_v27 }, NULL, NULL}, +{ "v28", NULL, 16, FPU_OFFSET(28), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, arm64_gcc::v28, fpu_v28 }, NULL, NULL}, +{ "v29", NULL, 16, FPU_OFFSET(29), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, arm64_gcc::v29, fpu_v29 }, NULL, NULL}, +{ "v30", NULL, 16, FPU_OFFSET(30), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, arm64_gcc::v30, fpu_v30 }, NULL, NULL}, +{ "v31", NULL, 16, FPU_OFFSET(31), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, arm64_gcc::v31, fpu_v31 }, NULL, NULL}, + +{ "fpsr", NULL, 4, FPU_OFFSET_NAME(fpsr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpsr }, NULL, NULL}, +{ "fpcr", NULL, 4, FPU_OFFSET_NAME(fpcr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpcr }, NULL, NULL}, + +{ "far", NULL, 8, EXC_OFFSET_NAME(far), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL}, +{ "esr", NULL, 4, EXC_OFFSET_NAME(esr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_esr }, NULL, NULL}, +{ "exception",NULL, 4, EXC_OFFSET_NAME(exception), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL}, + +{ DEFINE_DBG (bvr, 0) }, +{ DEFINE_DBG (bvr, 1) }, +{ DEFINE_DBG (bvr, 2) }, +{ DEFINE_DBG (bvr, 3) }, +{ DEFINE_DBG (bvr, 4) }, +{ DEFINE_DBG (bvr, 5) }, +{ DEFINE_DBG (bvr, 6) }, +{ DEFINE_DBG (bvr, 7) }, +{ DEFINE_DBG (bvr, 8) }, +{ DEFINE_DBG (bvr, 9) }, +{ DEFINE_DBG (bvr, 10) }, +{ DEFINE_DBG (bvr, 11) }, +{ DEFINE_DBG (bvr, 12) }, +{ DEFINE_DBG (bvr, 13) }, +{ DEFINE_DBG (bvr, 14) }, +{ DEFINE_DBG (bvr, 15) }, + +{ DEFINE_DBG (bcr, 0) }, +{ DEFINE_DBG (bcr, 1) }, +{ DEFINE_DBG (bcr, 2) }, +{ DEFINE_DBG (bcr, 3) }, +{ DEFINE_DBG (bcr, 4) }, +{ DEFINE_DBG (bcr, 5) }, +{ DEFINE_DBG (bcr, 6) }, +{ DEFINE_DBG (bcr, 7) }, +{ DEFINE_DBG (bcr, 8) }, +{ DEFINE_DBG (bcr, 9) }, +{ DEFINE_DBG (bcr, 10) }, +{ DEFINE_DBG (bcr, 11) }, +{ DEFINE_DBG (bcr, 12) }, +{ DEFINE_DBG (bcr, 13) }, +{ DEFINE_DBG (bcr, 14) }, +{ DEFINE_DBG (bcr, 15) }, + +{ DEFINE_DBG (wvr, 0) }, +{ DEFINE_DBG (wvr, 1) }, +{ DEFINE_DBG (wvr, 2) }, +{ DEFINE_DBG (wvr, 3) }, +{ DEFINE_DBG (wvr, 4) }, +{ DEFINE_DBG (wvr, 5) }, +{ DEFINE_DBG (wvr, 6) }, +{ DEFINE_DBG (wvr, 7) }, +{ DEFINE_DBG (wvr, 8) }, +{ DEFINE_DBG (wvr, 9) }, +{ DEFINE_DBG (wvr, 10) }, +{ DEFINE_DBG (wvr, 11) }, +{ DEFINE_DBG (wvr, 12) }, +{ DEFINE_DBG (wvr, 13) }, +{ DEFINE_DBG (wvr, 14) }, +{ DEFINE_DBG (wvr, 15) }, + +{ DEFINE_DBG (wcr, 0) }, +{ DEFINE_DBG (wcr, 1) }, +{ DEFINE_DBG (wcr, 2) }, +{ DEFINE_DBG (wcr, 3) }, +{ DEFINE_DBG (wcr, 4) }, +{ DEFINE_DBG (wcr, 5) }, +{ DEFINE_DBG (wcr, 6) }, +{ DEFINE_DBG (wcr, 7) }, +{ DEFINE_DBG (wcr, 8) }, +{ DEFINE_DBG (wcr, 9) }, +{ DEFINE_DBG (wcr, 10) }, +{ DEFINE_DBG (wcr, 11) }, +{ DEFINE_DBG (wcr, 12) }, +{ DEFINE_DBG (wcr, 13) }, +{ DEFINE_DBG (wcr, 14) }, +{ DEFINE_DBG (wcr, 15) } +}; + +#endif // DECLARE_REGISTER_INFOS_ARM64_STRUCT diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterInfos_i386.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h index 7c51656..fa152b4 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterInfos_i386.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h @@ -8,6 +8,8 @@ //===---------------------------------------------------------------------===// #include "llvm/Support/Compiler.h" +#include <stddef.h> + #ifdef DECLARE_REGISTER_INFOS_I386_STRUCT // Computes the offset of the given GPR in the user data area. @@ -24,7 +26,9 @@ (LLVM_EXTENSION offsetof(YMM, regname)) // Number of bytes needed to represent a FPR. +#if !defined(FPR_SIZE) #define FPR_SIZE(reg) sizeof(((FXSAVE*)NULL)->reg) +#endif // Number of bytes needed to represent the i'th FP register. #define FP_SIZE sizeof(((MMSReg*)NULL)->bytes) @@ -37,7 +41,7 @@ // Note that the size and offset will be updated by platform-specific classes. #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, sizeof(GPR::reg), GPR_OFFSET(reg), eEncodingUint, \ + { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_i386 }, NULL, NULL } #define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ @@ -129,10 +133,10 @@ g_register_infos_i386[] = DEFINE_FPR(fstat, fstat, LLDB_INVALID_REGNUM, dwarf_fstat_i386, LLDB_INVALID_REGNUM, gdb_fstat_i386), DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftag_i386), DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop_i386), - DEFINE_FPR(fiseg, ptr.i386.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_i386), - DEFINE_FPR(fioff, ptr.i386.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_i386), - DEFINE_FPR(foseg, ptr.i386.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_i386), - DEFINE_FPR(fooff, ptr.i386.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_i386), + DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_i386), + DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_i386), + DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_i386), + DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_i386), DEFINE_FPR(mxcsr, mxcsr, LLDB_INVALID_REGNUM, dwarf_mxcsr_i386, LLDB_INVALID_REGNUM, gdb_mxcsr_i386), DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterInfos_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h index 13526e3..187b8e9 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterInfos_mips64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h @@ -7,6 +7,8 @@ // //===---------------------------------------------------------------------===// +#include <stddef.h> + // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) \ (offsetof(GPR, regname)) @@ -15,7 +17,7 @@ // Note that the size and offset will be updated by platform-specific classes. #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, sizeof(GPR::reg), GPR_OFFSET(reg), eEncodingUint, \ + { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL } static RegisterInfo diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h index 86abdba..c4dc604 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h @@ -8,6 +8,8 @@ //===---------------------------------------------------------------------===// #include "llvm/Support/Compiler.h" +#include <stddef.h> + // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(GPR, regname)) @@ -39,7 +41,7 @@ // Note that the size and offset will be updated by platform-specific classes. #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, sizeof(GPR::reg), GPR_OFFSET(reg), eEncodingUint, \ + { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_x86_64 }, NULL, NULL } #define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ @@ -175,10 +177,10 @@ g_register_infos_x86_64[] = DEFINE_FPR(fstat, fstat, gcc_dwarf_fstat_x86_64, gcc_dwarf_fstat_x86_64, LLDB_INVALID_REGNUM, gdb_fstat_x86_64), DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftag_x86_64), DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop_x86_64), - DEFINE_FPR(fiseg, ptr.i386.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_x86_64), - DEFINE_FPR(fioff, ptr.i386.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_x86_64), - DEFINE_FPR(foseg, ptr.i386.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_x86_64), - DEFINE_FPR(fooff, ptr.i386.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_x86_64), + DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_x86_64), + DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_x86_64), + DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_x86_64), + DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_x86_64), DEFINE_FPR(mxcsr, mxcsr, gcc_dwarf_mxcsr_x86_64, gcc_dwarf_mxcsr_x86_64, LLDB_INVALID_REGNUM, gdb_mxcsr_x86_64), DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), @@ -343,10 +345,10 @@ do { UPDATE_FPR_INFO(fstat, fstat); UPDATE_FPR_INFO(ftag, ftag); UPDATE_FPR_INFO(fop, fop); - UPDATE_FPR_INFO(fiseg, ptr.i386.fiseg); - UPDATE_FPR_INFO(fioff, ptr.i386.fioff); - UPDATE_FPR_INFO(fooff, ptr.i386.fooff); - UPDATE_FPR_INFO(foseg, ptr.i386.foseg); + UPDATE_FPR_INFO(fiseg, ptr.i386_.fiseg); + UPDATE_FPR_INFO(fioff, ptr.i386_.fioff); + UPDATE_FPR_INFO(fooff, ptr.i386_.fooff); + UPDATE_FPR_INFO(foseg, ptr.i386_.foseg); UPDATE_FPR_INFO(mxcsr, mxcsr); UPDATE_FPR_INFO(mxcsrmask, mxcsrmask); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp index 51d2052..0e3e559 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -363,20 +363,30 @@ StopInfoMachException::CreateStopReasonWithMachException if (exc_code == 1) // EXC_I386_SGL { if (!exc_sub_code) - return StopInfo::CreateStopReasonToTrace(thread); - - // It's a watchpoint, then. - // The exc_sub_code indicates the data break address. - lldb::WatchpointSP wp_sp; - if (target) - wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); - if (wp_sp && wp_sp->IsEnabled()) { - // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. - // Set the hardware index if that's the case. - if (exc_data_count >=3) - wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); - return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); + // This looks like a plain trap. + // Have to check if there is a breakpoint here as well. When you single-step onto a trap, + // the single step stops you not to trap. Since we also do that check below, let's just use + // that logic. + is_actual_breakpoint = true; + is_trace_if_actual_breakpoint_missing = true; + } + else + { + + // It's a watchpoint, then. + // The exc_sub_code indicates the data break address. + lldb::WatchpointSP wp_sp; + if (target) + wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); + if (wp_sp && wp_sp->IsEnabled()) + { + // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. + // Set the hardware index if that's the case. + if (exc_data_count >=3) + wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); + return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); + } } } else if (exc_code == 2 || // EXC_I386_BPT @@ -429,6 +439,38 @@ StopInfoMachException::CreateStopReasonWithMachException } break; + case llvm::Triple::aarch64: + { + if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT + { + // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0 is set + return StopInfo::CreateStopReasonToTrace(thread); + } + if (exc_code == 0x102) // EXC_ARM_DA_DEBUG + { + // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled + // data break address from our watchpoint list. + lldb::WatchpointSP wp_sp; + if (target) + wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); + if (wp_sp && wp_sp->IsEnabled()) + { + // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. + // Set the hardware index if that's the case. + if (exc_data_count >= 3) + wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); + return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); + } + // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS + if (thread.GetTemporaryResumeState() == eStateStepping) + return StopInfo::CreateStopReasonToTrace(thread); + } + // It looks like exc_sub_code has the 4 bytes of the instruction that triggered the + // exception, i.e. our breakpoint opcode + is_actual_breakpoint = exc_code == 1; + break; + } + default: break; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp index 5db08e5..37fd4f4 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -347,7 +347,7 @@ bool UnwindLLDB::SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc, uint32_t starting_frame_num, bool pc_reg) { int64_t frame_num = starting_frame_num; - if (frame_num >= m_frames.size()) + if (static_cast<size_t>(frame_num) >= m_frames.size()) return false; // Never interrogate more than one level while looking for the saved pc value. If the value diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h new file mode 100644 index 0000000..c4706d5 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h @@ -0,0 +1,292 @@ +//===-- lldb-x86-register-enums.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_x86_register_enums_h +#define lldb_x86_register_enums_h + +namespace lldb_private +{ + + //--------------------------------------------------------------------------- + // Internal codes for all i386 registers. + //--------------------------------------------------------------------------- + enum + { + k_first_gpr_i386, + gpr_eax_i386 = k_first_gpr_i386, + gpr_ebx_i386, + gpr_ecx_i386, + gpr_edx_i386, + gpr_edi_i386, + gpr_esi_i386, + gpr_ebp_i386, + gpr_esp_i386, + gpr_eip_i386, + gpr_eflags_i386, + gpr_cs_i386, + gpr_fs_i386, + gpr_gs_i386, + gpr_ss_i386, + gpr_ds_i386, + gpr_es_i386, + + k_first_alias_i386, + gpr_ax_i386 = k_first_alias_i386, + gpr_bx_i386, + gpr_cx_i386, + gpr_dx_i386, + gpr_di_i386, + gpr_si_i386, + gpr_bp_i386, + gpr_sp_i386, + gpr_ah_i386, + gpr_bh_i386, + gpr_ch_i386, + gpr_dh_i386, + gpr_al_i386, + gpr_bl_i386, + gpr_cl_i386, + gpr_dl_i386, + k_last_alias_i386 = gpr_dl_i386, + + k_last_gpr_i386 = k_last_alias_i386, + + k_first_fpr_i386, + fpu_fctrl_i386 = k_first_fpr_i386, + fpu_fstat_i386, + fpu_ftag_i386, + fpu_fop_i386, + fpu_fiseg_i386, + fpu_fioff_i386, + fpu_foseg_i386, + fpu_fooff_i386, + fpu_mxcsr_i386, + fpu_mxcsrmask_i386, + fpu_st0_i386, + fpu_st1_i386, + fpu_st2_i386, + fpu_st3_i386, + fpu_st4_i386, + fpu_st5_i386, + fpu_st6_i386, + fpu_st7_i386, + fpu_mm0_i386, + fpu_mm1_i386, + fpu_mm2_i386, + fpu_mm3_i386, + fpu_mm4_i386, + fpu_mm5_i386, + fpu_mm6_i386, + fpu_mm7_i386, + fpu_xmm0_i386, + fpu_xmm1_i386, + fpu_xmm2_i386, + fpu_xmm3_i386, + fpu_xmm4_i386, + fpu_xmm5_i386, + fpu_xmm6_i386, + fpu_xmm7_i386, + k_last_fpr_i386 = fpu_xmm7_i386, + + k_first_avx_i386, + fpu_ymm0_i386 = k_first_avx_i386, + fpu_ymm1_i386, + fpu_ymm2_i386, + fpu_ymm3_i386, + fpu_ymm4_i386, + fpu_ymm5_i386, + fpu_ymm6_i386, + fpu_ymm7_i386, + k_last_avx_i386 = fpu_ymm7_i386, + + dr0_i386, + dr1_i386, + dr2_i386, + dr3_i386, + dr4_i386, + dr5_i386, + dr6_i386, + dr7_i386, + + k_num_registers_i386, + k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1, + k_num_fpr_registers_i386 = k_last_fpr_i386 - k_first_fpr_i386 + 1, + k_num_avx_registers_i386 = k_last_avx_i386 - k_first_avx_i386 + 1 + }; + + //--------------------------------------------------------------------------- + // Internal codes for all x86_64 registers. + //--------------------------------------------------------------------------- + enum + { + k_first_gpr_x86_64, + gpr_rax_x86_64 = k_first_gpr_x86_64, + gpr_rbx_x86_64, + gpr_rcx_x86_64, + gpr_rdx_x86_64, + gpr_rdi_x86_64, + gpr_rsi_x86_64, + gpr_rbp_x86_64, + gpr_rsp_x86_64, + gpr_r8_x86_64, + gpr_r9_x86_64, + gpr_r10_x86_64, + gpr_r11_x86_64, + gpr_r12_x86_64, + gpr_r13_x86_64, + gpr_r14_x86_64, + gpr_r15_x86_64, + gpr_rip_x86_64, + gpr_rflags_x86_64, + gpr_cs_x86_64, + gpr_fs_x86_64, + gpr_gs_x86_64, + gpr_ss_x86_64, + gpr_ds_x86_64, + gpr_es_x86_64, + + k_first_alias_x86_64, + gpr_eax_x86_64 = k_first_alias_x86_64, + gpr_ebx_x86_64, + gpr_ecx_x86_64, + gpr_edx_x86_64, + gpr_edi_x86_64, + gpr_esi_x86_64, + gpr_ebp_x86_64, + gpr_esp_x86_64, + gpr_r8d_x86_64, // Low 32 bits of r8 + gpr_r9d_x86_64, // Low 32 bits of r9 + gpr_r10d_x86_64, // Low 32 bits of r10 + gpr_r11d_x86_64, // Low 32 bits of r11 + gpr_r12d_x86_64, // Low 32 bits of r12 + gpr_r13d_x86_64, // Low 32 bits of r13 + gpr_r14d_x86_64, // Low 32 bits of r14 + gpr_r15d_x86_64, // Low 32 bits of r15 + gpr_ax_x86_64, + gpr_bx_x86_64, + gpr_cx_x86_64, + gpr_dx_x86_64, + gpr_di_x86_64, + gpr_si_x86_64, + gpr_bp_x86_64, + gpr_sp_x86_64, + gpr_r8w_x86_64, // Low 16 bits of r8 + gpr_r9w_x86_64, // Low 16 bits of r9 + gpr_r10w_x86_64, // Low 16 bits of r10 + gpr_r11w_x86_64, // Low 16 bits of r11 + gpr_r12w_x86_64, // Low 16 bits of r12 + gpr_r13w_x86_64, // Low 16 bits of r13 + gpr_r14w_x86_64, // Low 16 bits of r14 + gpr_r15w_x86_64, // Low 16 bits of r15 + gpr_ah_x86_64, + gpr_bh_x86_64, + gpr_ch_x86_64, + gpr_dh_x86_64, + gpr_al_x86_64, + gpr_bl_x86_64, + gpr_cl_x86_64, + gpr_dl_x86_64, + gpr_dil_x86_64, + gpr_sil_x86_64, + gpr_bpl_x86_64, + gpr_spl_x86_64, + gpr_r8l_x86_64, // Low 8 bits of r8 + gpr_r9l_x86_64, // Low 8 bits of r9 + gpr_r10l_x86_64, // Low 8 bits of r10 + gpr_r11l_x86_64, // Low 8 bits of r11 + gpr_r12l_x86_64, // Low 8 bits of r12 + gpr_r13l_x86_64, // Low 8 bits of r13 + gpr_r14l_x86_64, // Low 8 bits of r14 + gpr_r15l_x86_64, // Low 8 bits of r15 + k_last_alias_x86_64 = gpr_r15l_x86_64, + + k_last_gpr_x86_64 = k_last_alias_x86_64, + + k_first_fpr_x86_64, + fpu_fctrl_x86_64 = k_first_fpr_x86_64, + fpu_fstat_x86_64, + fpu_ftag_x86_64, + fpu_fop_x86_64, + fpu_fiseg_x86_64, + fpu_fioff_x86_64, + fpu_foseg_x86_64, + fpu_fooff_x86_64, + fpu_mxcsr_x86_64, + fpu_mxcsrmask_x86_64, + fpu_st0_x86_64, + fpu_st1_x86_64, + fpu_st2_x86_64, + fpu_st3_x86_64, + fpu_st4_x86_64, + fpu_st5_x86_64, + fpu_st6_x86_64, + fpu_st7_x86_64, + fpu_mm0_x86_64, + fpu_mm1_x86_64, + fpu_mm2_x86_64, + fpu_mm3_x86_64, + fpu_mm4_x86_64, + fpu_mm5_x86_64, + fpu_mm6_x86_64, + fpu_mm7_x86_64, + fpu_xmm0_x86_64, + fpu_xmm1_x86_64, + fpu_xmm2_x86_64, + fpu_xmm3_x86_64, + fpu_xmm4_x86_64, + fpu_xmm5_x86_64, + fpu_xmm6_x86_64, + fpu_xmm7_x86_64, + fpu_xmm8_x86_64, + fpu_xmm9_x86_64, + fpu_xmm10_x86_64, + fpu_xmm11_x86_64, + fpu_xmm12_x86_64, + fpu_xmm13_x86_64, + fpu_xmm14_x86_64, + fpu_xmm15_x86_64, + k_last_fpr_x86_64 = fpu_xmm15_x86_64, + + k_first_avx_x86_64, + fpu_ymm0_x86_64 = k_first_avx_x86_64, + fpu_ymm1_x86_64, + fpu_ymm2_x86_64, + fpu_ymm3_x86_64, + fpu_ymm4_x86_64, + fpu_ymm5_x86_64, + fpu_ymm6_x86_64, + fpu_ymm7_x86_64, + fpu_ymm8_x86_64, + fpu_ymm9_x86_64, + fpu_ymm10_x86_64, + fpu_ymm11_x86_64, + fpu_ymm12_x86_64, + fpu_ymm13_x86_64, + fpu_ymm14_x86_64, + fpu_ymm15_x86_64, + k_last_avx_x86_64 = fpu_ymm15_x86_64, + + dr0_x86_64, + dr1_x86_64, + dr2_x86_64, + dr3_x86_64, + dr4_x86_64, + dr5_x86_64, + dr6_x86_64, + 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, + k_num_fpr_registers_x86_64 = k_last_fpr_x86_64 - k_first_fpr_x86_64 + 1, + k_num_avx_registers_x86_64 = k_last_avx_x86_64 - k_first_avx_x86_64 + 1 + }; + +} + +#endif // #ifndef lldb_x86_register_enums_h diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 7ea5c89..5668167 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -17,12 +17,17 @@ #include "lldb/Core/Section.h" #include "lldb/Core/State.h" #include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Log.h" #include "lldb/Target/Target.h" #include "lldb/Target/DynamicLoader.h" -#include "ProcessPOSIXLog.h" +#include "lldb/Target/UnixSignals.h" + +#include "llvm/Support/ELF.h" #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h" +#include "Plugins/Process/Utility/FreeBSDSignals.h" +#include "Plugins/Process/Utility/LinuxSignals.h" // Project includes #include "ProcessElfCore.h" @@ -54,8 +59,25 @@ lldb::ProcessSP ProcessElfCore::CreateInstance (Target &target, Listener &listener, const FileSpec *crash_file) { lldb::ProcessSP process_sp; - if (crash_file) - process_sp.reset(new ProcessElfCore (target, listener, *crash_file)); + if (crash_file) + { + // Read enough data for a ELF32 header or ELF64 header + const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr); + + lldb::DataBufferSP data_sp (crash_file->ReadFileContents(0, header_size)); + if (data_sp && data_sp->GetByteSize() == header_size && + elf::ELFHeader::MagicBytesMatch (data_sp->GetBytes())) + { + elf::ELFHeader elf_header; + DataExtractor data(data_sp, lldb::eByteOrderLittle, 4); + lldb::offset_t data_offset = 0; + if (elf_header.Parse(data, &data_offset)) + { + if (elf_header.e_type == llvm::ELF::ET_CORE) + process_sp.reset(new ProcessElfCore (target, listener, *crash_file)); + } + } + } return process_sp; } @@ -66,7 +88,7 @@ ProcessElfCore::CanDebug(Target &target, bool plugin_specified_by_name) if (!m_core_module_sp && m_core_file.Exists()) { ModuleSpec core_module_spec(m_core_file, target.GetArchitecture()); - Error error (ModuleList::GetSharedModule (core_module_spec, m_core_module_sp, + Error error (ModuleList::GetSharedModule (core_module_spec, m_core_module_sp, NULL, NULL, NULL)); if (m_core_module_sp) { @@ -87,6 +109,7 @@ ProcessElfCore::ProcessElfCore(Target& target, Listener &listener, m_core_module_sp (), m_core_file (core_file), m_dyld_plugin_name (), + m_os(llvm::Triple::UnknownOS), m_thread_data_valid(false), m_thread_data(), m_core_aranges () @@ -154,21 +177,21 @@ ProcessElfCore::DoLoadCore () Error error; if (!m_core_module_sp) { - error.SetErrorString ("invalid core module"); + error.SetErrorString ("invalid core module"); return error; } ObjectFileELF *core = (ObjectFileELF *)(m_core_module_sp->GetObjectFile()); if (core == NULL) { - error.SetErrorString ("invalid core object file"); + error.SetErrorString ("invalid core object file"); return error; } const uint32_t num_segments = core->GetProgramHeaderCount(); if (num_segments == 0) { - error.SetErrorString ("core file has no sections"); + error.SetErrorString ("core file has no sections"); return error; } @@ -209,7 +232,25 @@ ProcessElfCore::DoLoadCore () // it to match the core file which is always single arch. ArchSpec arch (m_core_module_sp->GetArchitecture()); if (arch.IsValid()) - m_target.SetArchitecture(arch); + m_target.SetArchitecture(arch); + + switch (m_os) + { + case llvm::Triple::FreeBSD: + { + static UnixSignalsSP s_freebsd_signals_sp(new FreeBSDSignals ()); + SetUnixSignals(s_freebsd_signals_sp); + break; + } + case llvm::Triple::Linux: + { + static UnixSignalsSP s_linux_signals_sp(new process_linux::LinuxSignals ()); + SetUnixSignals(s_linux_signals_sp); + break; + } + default: + break; + } return error; } @@ -324,13 +365,17 @@ void ProcessElfCore::Clear() { m_thread_list.Clear(); + m_os = llvm::Triple::UnknownOS; + + static UnixSignalsSP s_default_unix_signals_sp(new UnixSignals()); + SetUnixSignals(s_default_unix_signals_sp); } void ProcessElfCore::Initialize() { static bool g_initialized = false; - + if (g_initialized == false) { g_initialized = true; @@ -378,7 +423,7 @@ ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, arch.GetMachine() == llvm::Triple::x86_64); int pr_version = data.GetU32(&offset); - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + Log *log (GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) { if (pr_version > 1) @@ -395,7 +440,7 @@ ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, offset += 4; // pr_pid if (lp64) offset += 4; - + size_t len = data.GetByteSize() - offset; thread_data.gpregset = DataExtractor(data, offset, len); } @@ -421,7 +466,7 @@ ParseFreeBSDThrMisc(ThreadData &thread_data, DataExtractor &data) /// a) Each thread context(2 or more NOTE entries) contained in its own segment (PT_NOTE) /// b) All thread context is stored in a single segment(PT_NOTE). /// This case is little tricker since while parsing we have to find where the -/// new thread starts. The current implementation marks beginning of +/// new thread starts. The current implementation marks beginning of /// new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry. /// For case (b) there may be either one NT_PRPSINFO per thread, or a single /// one that applies to all threads (depending on the platform type). @@ -468,6 +513,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader * DataExtractor note_data (segment_data, note_start, note_size); if (note.n_name == "FreeBSD") { + m_os = llvm::Triple::FreeBSD; switch (note.n_type) { case NT_FREEBSD_PRSTATUS: @@ -553,4 +599,3 @@ ProcessElfCore::GetAuxvData() lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(start, len)); return buffer; } - diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h index 1c1ed98..2fc2e4e 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -37,45 +37,45 @@ public: // Constructors and Destructors //------------------------------------------------------------------ static lldb::ProcessSP - CreateInstance (lldb_private::Target& target, - lldb_private::Listener &listener, + CreateInstance (lldb_private::Target& target, + lldb_private::Listener &listener, const lldb_private::FileSpec *crash_file_path); - + static void Initialize(); - + static void Terminate(); - + static lldb_private::ConstString GetPluginNameStatic(); - + static const char * GetPluginDescriptionStatic(); - + //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ - ProcessElfCore(lldb_private::Target& target, + ProcessElfCore(lldb_private::Target& target, lldb_private::Listener &listener, const lldb_private::FileSpec &core_file); - + virtual ~ProcessElfCore(); - + //------------------------------------------------------------------ // Check if a given Process //------------------------------------------------------------------ virtual bool CanDebug (lldb_private::Target &target, bool plugin_specified_by_name); - + //------------------------------------------------------------------ // Creating a new process, or attaching to an existing one //------------------------------------------------------------------ virtual lldb_private::Error DoLoadCore (); - + virtual lldb_private::DynamicLoader * GetDynamicLoader (); @@ -84,19 +84,19 @@ public: //------------------------------------------------------------------ virtual lldb_private::ConstString GetPluginName(); - + virtual uint32_t GetPluginVersion(); - + //------------------------------------------------------------------ // Process Control - //------------------------------------------------------------------ + //------------------------------------------------------------------ virtual lldb_private::Error DoDestroy (); - + virtual void RefreshStateAfterStop(); - + //------------------------------------------------------------------ // Process Queries //------------------------------------------------------------------ @@ -108,10 +108,10 @@ public: //------------------------------------------------------------------ virtual size_t ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error); - + virtual size_t DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error); - + virtual lldb::addr_t GetImageInfoAddress (); @@ -120,16 +120,16 @@ public: // Returns AUXV structure found in the core file const lldb::DataBufferSP - GetAuxvData(); + GetAuxvData() override; protected: void Clear ( ); - + virtual bool - UpdateThreadList (lldb_private::ThreadList &old_thread_list, + UpdateThreadList (lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list); - + private: //------------------------------------------------------------------ // For ProcessElfCore only @@ -142,6 +142,8 @@ private: std::string m_dyld_plugin_name; DISALLOW_COPY_AND_ASSIGN (ProcessElfCore); + llvm::Triple::OSType m_os; + // True if m_thread_contexts contains valid entries bool m_thread_data_valid; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp index b95a511..fbf397b 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp @@ -21,13 +21,9 @@ RegisterContextCorePOSIX_mips64::RegisterContextCorePOSIX_mips64(Thread &thread, const DataExtractor &fpregset) : RegisterContextPOSIX_mips64(thread, 0, register_info) { - size_t i; - lldb::offset_t offset = 0; - - for (i = 0; i < k_num_gpr_registers_mips64; i++) - { - m_reg[i] = gpregset.GetU64(&offset); - } + m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize())); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); } RegisterContextCorePOSIX_mips64::~RegisterContextCorePOSIX_mips64() @@ -63,10 +59,14 @@ RegisterContextCorePOSIX_mips64::WriteFPR() bool RegisterContextCorePOSIX_mips64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { - int reg_num = reg_info->byte_offset / 8; - assert(reg_num < k_num_gpr_registers_mips64); - value = m_reg[reg_num]; - return true; + lldb::offset_t offset = reg_info->byte_offset; + uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + if (offset == reg_info->byte_offset + reg_info->byte_size) + { + value = v; + return true; + } + return false; } bool diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h index 92e486b..ca29d4f 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h @@ -10,14 +10,15 @@ #ifndef liblldb_RegisterContextCorePOSIX_mips64_H_ #define liblldb_RegisterContextCorePOSIX_mips64_H_ -#include "Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h" +#include "lldb/Core/DataBufferHeap.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" class RegisterContextCorePOSIX_mips64 : public RegisterContextPOSIX_mips64 { public: RegisterContextCorePOSIX_mips64 (lldb_private::Thread &thread, - RegisterInfoInterface *register_info, + lldb_private::RegisterInfoInterface *register_info, const lldb_private::DataExtractor &gpregset, const lldb_private::DataExtractor &fpregset); @@ -52,7 +53,8 @@ protected: WriteFPR(); private: - uint64_t m_reg[40]; + lldb::DataBufferSP m_gpr_buffer; + lldb_private::DataExtractor m_gpr; }; #endif // #ifndef liblldb_RegisterContextCorePOSIX_mips64_H_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h index d4ea14f..ac0f49c 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h @@ -10,14 +10,14 @@ #ifndef liblldb_RegisterContextCorePOSIX_x86_64_H_ #define liblldb_RegisterContextCorePOSIX_x86_64_H_ -#include "Plugins/Process/POSIX/RegisterContextPOSIX_x86.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h" class RegisterContextCorePOSIX_x86_64 : public RegisterContextPOSIX_x86 { public: RegisterContextCorePOSIX_x86_64 (lldb_private::Thread &thread, - RegisterInfoInterface *register_info, + lldb_private::RegisterInfoInterface *register_info, const lldb_private::DataExtractor &gpregset, const lldb_private::DataExtractor &fpregset); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index cadcf53..d9f6cc0 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -8,11 +8,11 @@ //===----------------------------------------------------------------------===// #include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Unwind.h" -#include "ProcessPOSIXLog.h" #include "ThreadElfCore.h" #include "ProcessElfCore.h" @@ -74,7 +74,7 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) { RegisterContextSP reg_ctx_sp; uint32_t concrete_frame_idx = 0; - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + Log *log (GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (frame) concrete_frame_idx = frame->GetConcreteFrameIndex (); @@ -108,7 +108,7 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) } break; } - + case llvm::Triple::Linux: { switch (arch.GetMachine()) diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h index 2661edf..f1f00cf 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -40,7 +40,7 @@ struct ELFLinuxPrStatus int32_t si_errno; int16_t pr_cursig; - + uint64_t pr_sigpend; uint64_t pr_sighold; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 72600d8..1f4dd93 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -22,14 +22,21 @@ #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/Socket.h" #include "lldb/Host/TimeValue.h" #include "lldb/Target/Process.h" // Project includes #include "ProcessGDBRemoteLog.h" -#define DEBUGSERVER_BASENAME "debugserver" +#if defined(__APPLE__) +# define DEBUGSERVER_BASENAME "debugserver" +#else +# define DEBUGSERVER_BASENAME "lldb-gdbserver" +#endif using namespace lldb; using namespace lldb_private; @@ -321,6 +328,7 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac switch (status) { case eConnectionStatusTimedOut: + case eConnectionStatusInterrupted: timed_out = true; break; case eConnectionStatusSuccess: @@ -457,7 +465,8 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri assert (content_length <= m_bytes.size()); assert (total_length <= m_bytes.size()); assert (content_length <= total_length); - + const size_t content_end = content_start + content_length; + bool success = true; std::string &packet_str = packet.GetStringRef(); @@ -471,7 +480,45 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri if (!m_history.DidDumpToLog ()) m_history.Dump (log); - log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); + bool binary = false; + // Only detect binary for packets that start with a '$' and have a '#CC' checksum + if (m_bytes[0] == '$' && total_length > 4) + { + for (size_t i=0; !binary && i<total_length; ++i) + { + if (isprint(m_bytes[i]) == 0) + binary = true; + } + } + if (binary) + { + StreamString strm; + // Packet header... + strm.Printf("<%4" PRIu64 "> read packet: %c", (uint64_t)total_length, m_bytes[0]); + for (size_t i=content_start; i<content_end; ++i) + { + // Remove binary escaped bytes when displaying the packet... + const char ch = m_bytes[i]; + if (ch == 0x7d) + { + // 0x7d is the escape character. The next character is to + // be XOR'd with 0x20. + const char escapee = m_bytes[++i] ^ 0x20; + strm.Printf("%2.2x", escapee); + } + else + { + strm.Printf("%2.2x", (uint8_t)ch); + } + } + // Packet footer... + strm.Printf("%c%c%c", m_bytes[total_length-3], m_bytes[total_length-2], m_bytes[total_length-1]); + log->PutCString(strm.GetString().c_str()); + } + else + { + log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); + } } m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length); @@ -482,7 +529,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri // run-length encoding in the process. // Reserve enough byte for the most common case (no RLE used) packet_str.reserve(m_bytes.length()); - for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_start + content_length; ++c) + for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_end; ++c) { if (*c == '*') { @@ -610,6 +657,10 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, lldb_private::ProcessLaunchInfo &launch_info, uint16_t &out_port) { + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port); + out_port = in_port; Error error; // If we locate debugserver, keep that located version around @@ -622,24 +673,34 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, // to the debugserver to use and use it if we do. const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); if (env_debugserver_path) + { debugserver_file_spec.SetFile (env_debugserver_path, false); + if (log) + log->Printf ("GDBRemoteCommunication::%s() gdb-remote stub exe path set from environment variable: %s", __FUNCTION__, env_debugserver_path); + } else debugserver_file_spec = g_debugserver_file_spec; bool debugserver_exists = debugserver_file_spec.Exists(); if (!debugserver_exists) { // The debugserver binary is in the LLDB.framework/Resources - // directory. - if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) + // directory. + if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, debugserver_file_spec)) { - debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); + debugserver_file_spec.AppendPathComponent (DEBUGSERVER_BASENAME); debugserver_exists = debugserver_file_spec.Exists(); if (debugserver_exists) { + if (log) + log->Printf ("GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); + g_debugserver_file_spec = debugserver_file_spec; } else { + if (log) + log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); + g_debugserver_file_spec.Clear(); debugserver_file_spec.Clear(); } @@ -690,9 +751,9 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, // Binding to port zero, we need to figure out what port it ends up // using using a named pipe... FileSpec tmpdir_file_spec; - if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) + if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { - tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX"); + tmpdir_file_spec.AppendPathComponent("debugserver-named-pipe.XXXXXX"); strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path)); } else @@ -702,7 +763,7 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, if (::mktemp (named_pipe_path)) { -#if defined(_MSC_VER) +#if defined(_WIN32) if ( false ) #else if (::mkfifo(named_pipe_path, 0600) == 0) @@ -722,21 +783,28 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, { // No host and port given, so lets listen on our end and make the debugserver // connect to us.. - error = StartListenThread ("localhost", 0); + error = StartListenThread ("127.0.0.1", 0); if (error.Fail()) return error; ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); - out_port = connection->GetBoundPort(3); - assert (out_port != 0); - char port_cstr[32]; - snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_port); - // Send the host and port down that debugserver and specify an option - // so that it connects back to the port we are listening to in this process - debugserver_args.AppendArgument("--reverse-connect"); - debugserver_args.AppendArgument(port_cstr); + // Wait for 10 seconds to resolve the bound port + out_port = connection->GetListeningPort(10); + if (out_port > 0) + { + char port_cstr[32]; + snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_port); + // Send the host and port down that debugserver and specify an option + // so that it connects back to the port we are listening to in this process + debugserver_args.AppendArgument("--reverse-connect"); + debugserver_args.AppendArgument(port_cstr); + } + else + { + error.SetErrorString ("failed to bind to port 0 on 127.0.0.1"); + return error; + } } - const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); if (env_debugserver_log_file) @@ -751,7 +819,25 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } - + + // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back. + uint32_t env_var_index = 1; + bool has_env_var; + do + { + char env_var_name[64]; + snprintf (env_var_name, sizeof (env_var_name), "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++); + const char *extra_arg = getenv(env_var_name); + has_env_var = extra_arg != nullptr; + + if (has_env_var) + { + debugserver_args.AppendArgument (extra_arg); + if (log) + log->Printf ("GDBRemoteCommunication::%s adding env var %s contents to stub command line (%s)", __FUNCTION__, env_var_name, extra_arg); + } + } while (has_env_var); + // Close STDIN, STDOUT and STDERR. We might need to redirect them // to "/dev/null" if we run into any problems. launch_info.AppendCloseFileAction (STDIN_FILENO); @@ -760,31 +846,34 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, error = Host::LaunchProcess(launch_info); - if (named_pipe_path[0]) + if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { - File name_pipe_file; - error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); - if (error.Success()) + if (named_pipe_path[0]) { - char port_cstr[256]; - port_cstr[0] = '\0'; - size_t num_bytes = sizeof(port_cstr); - error = name_pipe_file.Read(port_cstr, num_bytes); - assert (error.Success()); - assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); - out_port = Args::StringToUInt32(port_cstr, 0); - name_pipe_file.Close(); + File name_pipe_file; + error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); + if (error.Success()) + { + char port_cstr[256]; + port_cstr[0] = '\0'; + size_t num_bytes = sizeof(port_cstr); + error = name_pipe_file.Read(port_cstr, num_bytes); + assert (error.Success()); + assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); + out_port = Args::StringToUInt32(port_cstr, 0); + name_pipe_file.Close(); + } + FileSystem::Unlink(named_pipe_path); + } + else if (listen) + { + + } + else + { + // Make sure we actually connect with the debugserver... + JoinListenThread(); } - Host::Unlink(named_pipe_path); - } - else if (listen) - { - - } - else - { - // Make sure we actually connect with the debugserver... - JoinListenThread(); } } else diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index d836111..b11d385 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -271,7 +271,7 @@ protected: lldb_private::Error - StartListenThread (const char *hostname = "localhost", + StartListenThread (const char *hostname = "127.0.0.1", uint16_t port = 0); bool diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index ab3bf7f..5e4ed76 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -17,6 +17,7 @@ #include <sstream> // Other libraries and framework includes +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include "lldb/Interpreter/Args.h" #include "lldb/Core/ConnectionFileDescriptor.h" @@ -26,7 +27,9 @@ #include "lldb/Core/StreamString.h" #include "lldb/Host/Endian.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Target/Target.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -37,7 +40,7 @@ using namespace lldb; using namespace lldb_private; -#ifdef LLDB_DISABLE_POSIX +#if defined(LLDB_DISABLE_POSIX) && !defined(SIGSTOP) #define SIGSTOP 17 #endif @@ -56,7 +59,9 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_supports_vCont_s (eLazyBoolCalculate), m_supports_vCont_S (eLazyBoolCalculate), m_qHostInfo_is_valid (eLazyBoolCalculate), + m_curr_pid_is_valid (eLazyBoolCalculate), m_qProcessInfo_is_valid (eLazyBoolCalculate), + m_qGDBServerVersion_is_valid (eLazyBoolCalculate), m_supports_alloc_dealloc_memory (eLazyBoolCalculate), m_supports_memory_region_info (eLazyBoolCalculate), m_supports_watchpoint_support_info (eLazyBoolCalculate), @@ -65,10 +70,14 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply (eLazyBoolCalculate), m_supports_p (eLazyBoolCalculate), + m_supports_x (eLazyBoolCalculate), + m_avoid_g_packets (eLazyBoolCalculate), m_supports_QSaveRegisterState (eLazyBoolCalculate), + m_supports_qXfer_auxv_read (eLazyBoolCalculate), m_supports_qXfer_libraries_read (eLazyBoolCalculate), m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate), m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate), + m_supports_jThreadExtendedInfo (eLazyBoolCalculate), m_supports_qProcessInfoPID (true), m_supports_qfProcessInfo (true), m_supports_qUserName (true), @@ -81,6 +90,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_supports_z4 (true), m_supports_QEnvironment (true), m_supports_QEnvironmentHexEncoded (true), + m_curr_pid (LLDB_INVALID_PROCESS_ID), m_curr_tid (LLDB_INVALID_THREAD_ID), m_curr_tid_run (LLDB_INVALID_THREAD_ID), m_num_supported_hardware_watchpoints (0), @@ -90,6 +100,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_async_result (PacketResult::Success), m_async_response (), m_async_signal (-1), + m_interrupt_sent (false), m_thread_id_to_used_usec_map (), m_host_arch(), m_process_arch(), @@ -99,6 +110,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_os_build (), m_os_kernel (), m_hostname (), + m_gdb_server_name(), + m_gdb_server_version(UINT32_MAX), m_default_packet_timeout (0), m_max_packet_size (0) { @@ -187,6 +200,16 @@ GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported () return (m_supports_qXfer_libraries_read == eLazyBoolYes); } +bool +GDBRemoteCommunicationClient::GetQXferAuxvReadSupported () +{ + if (m_supports_qXfer_auxv_read == eLazyBoolCalculate) + { + GetRemoteQSupported(); + } + return (m_supports_qXfer_auxv_read == eLazyBoolYes); +} + uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() { @@ -205,8 +228,18 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported () m_send_acks = true; m_supports_not_sending_acks = eLazyBoolNo; + // This is the first real packet that we'll send in a debug session and it may take a little + // longer than normal to receive a reply. Wait at least 6 seconds for a reply to this packet. + + const uint32_t minimum_timeout = 6; + uint32_t old_timeout = GetPacketTimeoutInMicroSeconds() / lldb_private::TimeValue::MicroSecPerSec; + SetPacketTimeout (std::max (old_timeout, minimum_timeout)); + StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success) + PacketResult packet_send_result = SendPacketAndWaitForResponse("QStartNoAckMode", response, false); + SetPacketTimeout (old_timeout); + + if (packet_send_result == PacketResult::Success) { if (response.IsOKResponse()) { @@ -287,13 +320,18 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_vCont_s = eLazyBoolCalculate; m_supports_vCont_S = eLazyBoolCalculate; m_supports_p = eLazyBoolCalculate; + m_supports_x = eLazyBoolCalculate; m_supports_QSaveRegisterState = eLazyBoolCalculate; m_qHostInfo_is_valid = eLazyBoolCalculate; + m_curr_pid_is_valid = eLazyBoolCalculate; m_qProcessInfo_is_valid = eLazyBoolCalculate; + m_qGDBServerVersion_is_valid = eLazyBoolCalculate; m_supports_alloc_dealloc_memory = eLazyBoolCalculate; m_supports_memory_region_info = eLazyBoolCalculate; m_prepare_for_reg_writing_reply = eLazyBoolCalculate; m_attach_or_wait_reply = eLazyBoolCalculate; + m_avoid_g_packets = eLazyBoolCalculate; + m_supports_qXfer_auxv_read = eLazyBoolCalculate; m_supports_qXfer_libraries_read = eLazyBoolCalculate; m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; @@ -310,8 +348,18 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_z4 = true; m_supports_QEnvironment = true; m_supports_QEnvironmentHexEncoded = true; + m_host_arch.Clear(); m_process_arch.Clear(); + m_os_version_major = UINT32_MAX; + m_os_version_minor = UINT32_MAX; + m_os_version_update = UINT32_MAX; + m_os_build.clear(); + m_os_kernel.clear(); + m_hostname.clear(); + m_gdb_server_name.clear(); + m_gdb_server_version = UINT32_MAX; + m_default_packet_timeout = 0; m_max_packet_size = 0; } @@ -320,8 +368,9 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported () { // Clear out any capabilities we expect to see in the qSupported response - m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; + m_supports_qXfer_auxv_read = eLazyBoolNo; m_supports_qXfer_libraries_read = eLazyBoolNo; + m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; m_supports_augmented_libraries_svr4_read = eLazyBoolNo; m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if not, we assume no limit @@ -331,6 +380,8 @@ GDBRemoteCommunicationClient::GetRemoteQSupported () /*send_async=*/false) == PacketResult::Success) { const char *response_cstr = response.GetStringRef().c_str(); + if (::strstr (response_cstr, "qXfer:auxv:read+")) + m_supports_qXfer_auxv_read = eLazyBoolYes; if (::strstr (response_cstr, "qXfer:libraries-svr4:read+")) m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; if (::strstr (response_cstr, "augmented-libraries-svr4-read")) @@ -457,6 +508,42 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid) return m_supports_p; } +bool +GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported () +{ + if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate) + { + StringExtractorGDBRemote response; + m_supports_jThreadExtendedInfo = eLazyBoolNo; + if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + { + m_supports_jThreadExtendedInfo = eLazyBoolYes; + } + } + } + return m_supports_jThreadExtendedInfo; +} + +bool +GDBRemoteCommunicationClient::GetxPacketSupported () +{ + if (m_supports_x == eLazyBoolCalculate) + { + StringExtractorGDBRemote response; + m_supports_x = eLazyBoolNo; + char packet[256]; + snprintf (packet, sizeof (packet), "x0,0"); + if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + m_supports_x = eLazyBoolYes; + } + } + return m_supports_x; +} + GDBRemoteCommunicationClient::PacketResult GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses ( @@ -502,11 +589,8 @@ GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses { return PacketResult::ErrorReplyInvalid; } - // Skip past m or l - const char *s = this_string.c_str() + 1; - - // Concatenate the result so far - response_string += s; + // Concatenate the result so far (skipping 'm' or 'l') + response_string.append(this_string, 1, std::string::npos); if (first_char == 'l') // We're done return PacketResult::Success; @@ -550,7 +634,6 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse PacketResult packet_result = PacketResult::ErrorSendFailed; Mutex::Locker locker; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - size_t response_len = 0; if (GetSequenceMutex (locker)) { packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); @@ -588,7 +671,6 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse // Swap the response buffer to avoid malloc and string copy response.GetStringRef().swap (m_async_response.GetStringRef()); - response_len = response.GetStringRef().size(); packet_result = m_async_result; } else @@ -772,6 +854,8 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str()); if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) state = eStateInvalid; + else + m_interrupt_sent = false; m_private_is_running.SetValue (true, eBroadcastAlways); } @@ -1047,7 +1131,7 @@ GDBRemoteCommunicationClient::SendAsyncSignal (int signo) // then the caller that requested the interrupt will want to keep the sequence // locked down so that no one else can send packets while the caller has control. // This function usually gets called when we are running and need to stop the -// target. It can also be used when we are running and and we need to do something +// target. It can also be used when we are running and we need to do something // else (like read/write memory), so we need to interrupt the running process // (gdb remote protocol requires this), and do what we need to do, then resume. @@ -1128,13 +1212,40 @@ GDBRemoteCommunicationClient::SendInterrupt lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID () { - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success) + if (m_curr_pid_is_valid == eLazyBoolYes) + return m_curr_pid; + + // First try to retrieve the pid via the qProcessInfo request. + GetCurrentProcessInfo (); + if (m_curr_pid_is_valid == eLazyBoolYes) + { + // We really got it. + return m_curr_pid; + } + else { - if (response.GetChar() == 'Q') - if (response.GetChar() == 'C') - return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID); + // If we don't get a response for qProcessInfo, check if $qC gives us a result. + // $qC only returns a real process id on older debugserver and lldb-platform stubs. + // The gdb remote protocol documents $qC as returning the thread id, which newer + // debugserver and lldb-gdbserver stubs return correctly. + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success) + { + if (response.GetChar() == 'Q') + { + if (response.GetChar() == 'C') + { + m_curr_pid = response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID); + if (m_curr_pid != LLDB_INVALID_PROCESS_ID) + { + m_curr_pid_is_valid = eLazyBoolYes; + return m_curr_pid; + } + } + } + } } + return LLDB_INVALID_PROCESS_ID; } @@ -1168,7 +1279,7 @@ int GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info) { // Since we don't get the send argv0 separate from the executable path, we need to - // make sure to use the actual exectuable path found in the launch_info... + // make sure to use the actual executable path found in the launch_info... std::vector<const char *> argv; FileSpec exe_file = launch_info.GetExecutableFile(); std::string exe_path; @@ -1304,6 +1415,41 @@ GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch) return -1; } +int +GDBRemoteCommunicationClient::SendLaunchEventDataPacket (char const *data, bool *was_supported) +{ + if (data && *data != '\0') + { + StreamString packet; + packet.Printf("QSetProcessEvent:%s", data); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + { + if (was_supported) + *was_supported = true; + return 0; + } + else if (response.IsUnsupportedResponse()) + { + if (was_supported) + *was_supported = false; + return -1; + } + else + { + uint8_t error = response.GetError(); + if (was_supported) + *was_supported = true; + if (error) + return error; + } + } + } + return -1; +} + bool GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major, uint32_t &minor, @@ -1384,10 +1530,75 @@ GDBRemoteCommunicationClient::GetProcessArchitecture () return m_process_arch; } +bool +GDBRemoteCommunicationClient::GetGDBServerVersion() +{ + if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) + { + m_gdb_server_name.clear(); + m_gdb_server_version = 0; + m_qGDBServerVersion_is_valid = eLazyBoolNo; + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success) + { + if (response.IsNormalResponse()) + { + std::string name; + std::string value; + bool success = false; + while (response.GetNameColonValue(name, value)) + { + if (name.compare("name") == 0) + { + success = true; + m_gdb_server_name.swap(value); + } + else if (name.compare("version") == 0) + { + size_t dot_pos = value.find('.'); + if (dot_pos != std::string::npos) + value[dot_pos] = '\0'; + const uint32_t version = Args::StringToUInt32(value.c_str(), UINT32_MAX, 0); + if (version != UINT32_MAX) + { + success = true; + m_gdb_server_version = version; + } + } + } + if (success) + m_qGDBServerVersion_is_valid = eLazyBoolYes; + } + } + } + return m_qGDBServerVersion_is_valid == eLazyBoolYes; +} + +const char * +GDBRemoteCommunicationClient::GetGDBServerProgramName() +{ + if (GetGDBServerVersion()) + { + if (!m_gdb_server_name.empty()) + return m_gdb_server_name.c_str(); + } + return NULL; +} + +uint32_t +GDBRemoteCommunicationClient::GetGDBServerProgramVersion() +{ + if (GetGDBServerVersion()) + return m_gdb_server_version; + return 0; +} bool GDBRemoteCommunicationClient::GetHostInfo (bool force) { + Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS)); + if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) { m_qHostInfo_is_valid = eLazyBoolNo; @@ -1432,10 +1643,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) } else if (name.compare("triple") == 0) { - // The triple comes as ASCII hex bytes since it contains '-' chars - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (triple); + triple.swap(value); ++num_keys_decoded; } else if (name.compare ("distribution_id") == 0) @@ -1548,6 +1756,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { switch (m_host_arch.GetMachine()) { + case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::thumb: os_name = "ios"; @@ -1588,6 +1797,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { switch (m_host_arch.GetMachine()) { + case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::thumb: host_triple.setOS(llvm::Triple::IOS); @@ -1619,6 +1829,9 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { assert (byte_order == m_host_arch.GetByteOrder()); } + + if (log) + log->Printf ("GDBRemoteCommunicationClient::%s parsed host architecture as %s, triple as %s from triple text %s", __FUNCTION__, m_host_arch.GetArchitectureName () ? m_host_arch.GetArchitectureName () : "<null-arch-name>", m_host_arch.GetTriple ().getTriple ().c_str(), triple.c_str ()); } if (!distribution_id.empty ()) m_host_arch.SetDistributionId (distribution_id.c_str ()); @@ -1682,7 +1895,9 @@ GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions) StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { - if (!response.IsErrorResponse()) + if (response.IsUnsupportedResponse()) + m_supports_alloc_dealloc_memory = eLazyBoolNo; + else if (!response.IsErrorResponse()) return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); } else @@ -1705,7 +1920,9 @@ GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr) StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { - if (response.IsOKResponse()) + if (response.IsUnsupportedResponse()) + m_supports_alloc_dealloc_memory = eLazyBoolNo; + else if (response.IsOKResponse()) return true; } else @@ -1746,14 +1963,16 @@ GDBRemoteCommunicationClient::Detach (bool keep_stopped) } else { - PacketResult packet_result = SendPacket ("D1", 2); + StringExtractorGDBRemote response; + PacketResult packet_result = SendPacketAndWaitForResponse ("D1", 1, response, false); if (packet_result != PacketResult::Success) error.SetErrorString ("Sending extended disconnect packet failed."); } } else { - PacketResult packet_result = SendPacket ("D", 1); + StringExtractorGDBRemote response; + PacketResult packet_result = SendPacketAndWaitForResponse ("D", 1, response, false); if (packet_result != PacketResult::Success) error.SetErrorString ("Sending disconnect packet failed."); } @@ -2051,6 +2270,25 @@ GDBRemoteCommunicationClient::SetDisableASLR (bool enable) return -1; } +int +GDBRemoteCommunicationClient::SetDetachOnError (bool enable) +{ + char packet[32]; + const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDetachOnError:%i", enable ? 1 : 0); + assert (packet_len < (int)sizeof(packet)); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + } + return -1; +} + + bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info) { @@ -2093,10 +2331,6 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot } else if (name.compare("triple") == 0) { - // The triple comes as ASCII hex bytes since it contains '-' chars - extractor.GetStringRef().swap(value); - extractor.SetFilePos(0); - extractor.GetHexByteString (value); process_info.GetArchitecture ().SetTriple (value.c_str()); } else if (name.compare("name") == 0) @@ -2192,8 +2426,8 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () std::string triple; uint32_t pointer_byte_size = 0; StringExtractor extractor; - ByteOrder byte_order = eByteOrderInvalid; uint32_t num_keys_decoded = 0; + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; while (response.GetNameColonValue(name, value)) { if (name.compare("cputype") == 0) @@ -2208,6 +2442,11 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () if (sub != 0) ++num_keys_decoded; } + else if (name.compare("triple") == 0) + { + triple = value; + ++num_keys_decoded; + } else if (name.compare("ostype") == 0) { os_name.swap (value); @@ -2220,15 +2459,10 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () } else if (name.compare("endian") == 0) { - ++num_keys_decoded; - if (value.compare("little") == 0) - byte_order = eByteOrderLittle; - else if (value.compare("big") == 0) - byte_order = eByteOrderBig; - else if (value.compare("pdp") == 0) - byte_order = eByteOrderPDP; - else - --num_keys_decoded; + if (value.compare("little") == 0 || + value.compare("big") == 0 || + value.compare("pdp") == 0) + ++num_keys_decoded; } else if (name.compare("ptrsize") == 0) { @@ -2236,20 +2470,42 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () if (pointer_byte_size != 0) ++num_keys_decoded; } + else if (name.compare("pid") == 0) + { + pid = Args::StringToUInt64(value.c_str(), 0, 16); + if (pid != LLDB_INVALID_PROCESS_ID) + ++num_keys_decoded; + } } if (num_keys_decoded > 0) m_qProcessInfo_is_valid = eLazyBoolYes; - if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty()) + if (pid != LLDB_INVALID_PROCESS_ID) + { + m_curr_pid_is_valid = eLazyBoolYes; + m_curr_pid = pid; + } + + // Set the ArchSpec from the triple if we have it. + if (!triple.empty ()) + { + m_process_arch.SetTriple (triple.c_str ()); + if (pointer_byte_size) + { + assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); + } + } + else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty()) { m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub); if (pointer_byte_size) { assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); } + m_process_arch.GetTriple().setOSName(llvm::StringRef (os_name)); m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name)); - return true; } + return true; } } else @@ -2333,7 +2589,7 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat const ArchSpec &match_arch = match_info.GetProcessInfo().GetArchitecture(); const llvm::Triple &triple = match_arch.GetTriple(); packet.PutCString("triple:"); - packet.PutCStringAsRawHex8(triple.getTriple().c_str()); + packet.PutCString(triple.getTriple().c_str()); packet.PutChar (';'); } } @@ -2429,8 +2685,8 @@ GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets) { static uint32_t g_send_sizes[] = { 0, 64, 128, 512, 1024 }; static uint32_t g_recv_sizes[] = { 0, 64, 128, 512, 1024 }; //, 4*1024, 8*1024, 16*1024, 32*1024, 48*1024, 64*1024, 96*1024, 128*1024 }; - const size_t k_num_send_sizes = sizeof(g_send_sizes)/sizeof(uint32_t); - const size_t k_num_recv_sizes = sizeof(g_recv_sizes)/sizeof(uint32_t); + const size_t k_num_send_sizes = llvm::array_lengthof(g_send_sizes); + const size_t k_num_recv_sizes = llvm::array_lengthof(g_recv_sizes); const uint64_t k_recv_amount = 4*1024*1024; // Receive 4MB for (uint32_t send_idx = 0; send_idx < k_num_send_sizes; ++send_idx) { @@ -2539,7 +2795,7 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const hostname = remote_accept_hostname; else { - if (Host::GetHostname (hostname)) + if (HostInfo::GetHostname(hostname)) { // Make the GDB server we launch only accept connections from this host stream.Printf("host:%s;", hostname.c_str()); @@ -2687,7 +2943,7 @@ GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, type, addr, length); - // Check we havent overwritten the end of the packet buffer + // Check we haven't overwritten the end of the packet buffer assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; // Try to send the breakpoint packet, and check that it was correctly sent @@ -2715,7 +2971,7 @@ GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, } } } - // Signal generic faliure + // Signal generic failure return UINT8_MAX; } @@ -2977,7 +3233,7 @@ GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &fil else { const uint32_t mode = response.GetS32(-1); - if (mode == -1) + if (static_cast<int32_t>(mode) == -1) { if (response.GetChar() == ',') { @@ -3217,6 +3473,38 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s } bool +GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process) +{ + // Some targets have issues with g/G packets and we need to avoid using them + if (m_avoid_g_packets == eLazyBoolCalculate) + { + if (process) + { + m_avoid_g_packets = eLazyBoolNo; + const ArchSpec &arch = process->GetTarget().GetArchitecture(); + if (arch.IsValid() + && arch.GetTriple().getVendor() == llvm::Triple::Apple + && arch.GetTriple().getOS() == llvm::Triple::IOS + && arch.GetTriple().getArch() == llvm::Triple::aarch64) + { + m_avoid_g_packets = eLazyBoolYes; + uint32_t gdb_server_version = GetGDBServerProgramVersion(); + if (gdb_server_version != 0) + { + const char *gdb_server_name = GetGDBServerProgramName(); + if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0) + { + if (gdb_server_version >= 310) + m_avoid_g_packets = eLazyBoolNo; + } + } + } + } + } + return m_avoid_g_packets == eLazyBoolYes; +} + +bool GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response) { Mutex::Locker locker; @@ -3309,7 +3597,7 @@ GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save bool GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id) { - // We use the "m_supports_QSaveRegisterState" variable here becuase the + // We use the "m_supports_QSaveRegisterState" variable here because the // QSaveRegisterState and QRestoreRegisterState packets must both be supported in // order to be useful if (m_supports_QSaveRegisterState == eLazyBoolNo) diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index a1e982b..fddcd6c 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -92,7 +92,7 @@ public: // indicates if the packet was send and any response was received // even in the response is UNIMPLEMENTED. If the packet failed to // get a response, then false is returned. This quickly tells us - // if we were able to connect and communicte with the remote GDB + // if we were able to connect and communicate with the remote GDB // server bool QueryNoAckModeSupported (); @@ -159,6 +159,10 @@ public: int SendLaunchArchPacket (const char *arch); + + int + SendLaunchEventDataPacket (const char *data, bool *was_supported = NULL); + //------------------------------------------------------------------ /// Sends a "vAttach:PID" where PID is in hex. /// @@ -201,13 +205,25 @@ public: /// be launched with the 'A' packet. /// /// @param[in] enable - /// A boolean value indicating wether to disable ASLR or not. + /// A boolean value indicating whether to disable ASLR or not. /// /// @return /// Zero if the for success, or an error code for failure. //------------------------------------------------------------------ int SetDisableASLR (bool enable); + + //------------------------------------------------------------------ + /// Sets the DetachOnError flag to \a enable for the process controlled by the stub. + /// + /// @param[in] enable + /// A boolean value indicating whether to detach on error or not. + /// + /// @return + /// Zero if the for success, or an error code for failure. + //------------------------------------------------------------------ + int + SetDetachOnError (bool enable); //------------------------------------------------------------------ /// Sets the working directory to \a path for a process that will @@ -217,7 +233,7 @@ public: /// directory for the platform process. /// /// @param[in] path - /// The path to a directory to use when launching our processs + /// The path to a directory to use when launching our process /// /// @return /// Zero if the for success, or an error code for failure. @@ -279,6 +295,9 @@ public: GetpPacketSupported (lldb::tid_t tid); bool + GetxPacketSupported (); + + bool GetVAttachOrWaitSupported (); bool @@ -384,6 +403,9 @@ public: SetCurrentThreadForRun (uint64_t tid); bool + GetQXferAuxvReadSupported (); + + bool GetQXferLibrariesReadSupported (); bool @@ -491,7 +513,19 @@ public: bool RestoreRegisterState (lldb::tid_t tid, uint32_t save_id); + + const char * + GetGDBServerProgramName(); + uint32_t + GetGDBServerProgramVersion(); + + bool + AvoidGPackets(ProcessGDBRemote *process); + + bool + GetThreadExtendedInfoSupported(); + protected: PacketResult @@ -502,6 +536,9 @@ protected: bool GetCurrentProcessInfo (); + bool + GetGDBServerVersion(); + //------------------------------------------------------------------ // Classes that inherit from GDBRemoteCommunicationClient can see and modify these //------------------------------------------------------------------ @@ -515,7 +552,9 @@ protected: lldb_private::LazyBool m_supports_vCont_s; lldb_private::LazyBool m_supports_vCont_S; lldb_private::LazyBool m_qHostInfo_is_valid; + lldb_private::LazyBool m_curr_pid_is_valid; lldb_private::LazyBool m_qProcessInfo_is_valid; + lldb_private::LazyBool m_qGDBServerVersion_is_valid; lldb_private::LazyBool m_supports_alloc_dealloc_memory; lldb_private::LazyBool m_supports_memory_region_info; lldb_private::LazyBool m_supports_watchpoint_support_info; @@ -524,10 +563,14 @@ protected: lldb_private::LazyBool m_attach_or_wait_reply; lldb_private::LazyBool m_prepare_for_reg_writing_reply; lldb_private::LazyBool m_supports_p; + lldb_private::LazyBool m_supports_x; + lldb_private::LazyBool m_avoid_g_packets; lldb_private::LazyBool m_supports_QSaveRegisterState; + lldb_private::LazyBool m_supports_qXfer_auxv_read; lldb_private::LazyBool m_supports_qXfer_libraries_read; lldb_private::LazyBool m_supports_qXfer_libraries_svr4_read; lldb_private::LazyBool m_supports_augmented_libraries_svr4_read; + lldb_private::LazyBool m_supports_jThreadExtendedInfo; bool m_supports_qProcessInfoPID:1, @@ -543,7 +586,7 @@ protected: m_supports_QEnvironment:1, m_supports_QEnvironmentHexEncoded:1; - + lldb::pid_t m_curr_pid; lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for continue, step, etc @@ -570,6 +613,8 @@ protected: std::string m_os_build; std::string m_os_kernel; std::string m_hostname; + std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if qGDBServerVersion is not supported + uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if qGDBServerVersion is not supported uint32_t m_default_packet_timeout; uint64_t m_max_packet_size; // as returned by qSupported diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index df95542..ffcdd16 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -9,24 +9,38 @@ #include <errno.h> +#include "lldb/Host/Config.h" + #include "GDBRemoteCommunicationServer.h" #include "lldb/Core/StreamGDBRemote.h" // C Includes // C++ Includes +#include <cstring> +#include <chrono> +#include <thread> + // Other libraries and framework includes #include "llvm/ADT/Triple.h" #include "lldb/Interpreter/Args.h" #include "lldb/Core/ConnectionFileDescriptor.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/Log.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamString.h" +#include "lldb/Host/Debug.h" #include "lldb/Host/Endian.h" #include "lldb/Host/File.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Target/FileAction.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" +#include "lldb/Target/NativeRegisterContext.h" +#include "Host/common/NativeProcessProtocol.h" +#include "Host/common/NativeThreadProtocol.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -37,6 +51,22 @@ using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- +// GDBRemote Errors +//---------------------------------------------------------------------- + +namespace +{ + enum GDBRemoteServerError + { + // Set to the first unused error number in literal form below + eErrorFirst = 29, + eErrorNoProcess = eErrorFirst, + eErrorResume, + eErrorExitStatus + }; +} + +//---------------------------------------------------------------------- // GDBRemoteCommunicationServer constructor //---------------------------------------------------------------------- GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : @@ -50,12 +80,28 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : m_proc_infos (), m_proc_infos_index (0), m_port_map (), - m_port_offset(0) + m_port_offset(0), + m_current_tid (LLDB_INVALID_THREAD_ID), + m_continue_tid (LLDB_INVALID_THREAD_ID), + m_debugged_process_mutex (Mutex::eMutexTypeRecursive), + m_debugged_process_sp (), + m_debugger_sp (), + m_stdio_communication ("process.stdio"), + m_exit_now (false), + m_inferior_prev_state (StateType::eStateInvalid), + m_thread_suffix_supported (false), + m_list_threads_in_stop_reply (false), + m_active_auxv_buffer_sp (), + m_saved_registers_mutex (), + m_saved_registers_map (), + m_next_saved_registers_id (1) { + assert(is_platform && "must be lldb-platform if debugger is not specified"); } GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform, - const lldb::PlatformSP& platform_sp) : + const lldb::PlatformSP& platform_sp, + lldb::DebuggerSP &debugger_sp) : GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), m_platform_sp (platform_sp), m_async_thread (LLDB_INVALID_HOST_THREAD), @@ -66,9 +112,24 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform, m_proc_infos (), m_proc_infos_index (0), m_port_map (), - m_port_offset(0) + m_port_offset(0), + m_current_tid (LLDB_INVALID_THREAD_ID), + m_continue_tid (LLDB_INVALID_THREAD_ID), + m_debugged_process_mutex (Mutex::eMutexTypeRecursive), + m_debugged_process_sp (), + m_debugger_sp (debugger_sp), + m_stdio_communication ("process.stdio"), + m_exit_now (false), + m_inferior_prev_state (StateType::eStateInvalid), + m_thread_suffix_supported (false), + m_list_threads_in_stop_reply (false), + m_active_auxv_buffer_sp (), + m_saved_registers_mutex (), + m_saved_registers_map (), + m_next_saved_registers_id (1) { assert(platform_sp); + assert((is_platform || debugger_sp) && "must specify non-NULL debugger_sp when lldb-gdbserver"); } //---------------------------------------------------------------------- @@ -78,37 +139,14 @@ GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() { } - -//void * -//GDBRemoteCommunicationServer::AsyncThread (void *arg) -//{ -// GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg; -// -// Log *log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); -// if (log) -// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID()); -// -// StringExtractorGDBRemote packet; -// -// while () -// { -// if (packet. -// } -// -// if (log) -// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID()); -// -// process->m_async_thread = LLDB_INVALID_HOST_THREAD; -// return NULL; -//} -// -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, Error &error, bool &interrupt, bool &quit) { StringExtractorGDBRemote packet; + PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec); if (packet_result == PacketResult::Success) { @@ -124,11 +162,6 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, quit = true; break; - case StringExtractorGDBRemote::eServerPacketType_interrupt: - error.SetErrorString("interrupt received"); - interrupt = true; - break; - default: case StringExtractorGDBRemote::eServerPacketType_unimplemented: packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); @@ -164,6 +197,7 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_k: packet_result = Handle_k (packet); + quit = true; break; case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess: @@ -174,6 +208,10 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, packet_result = Handle_qGroupName (packet); break; + case StringExtractorGDBRemote::eServerPacketType_qProcessInfo: + packet_result = Handle_qProcessInfo (packet); + break; + case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID: packet_result = Handle_qProcessInfoPID (packet); break; @@ -202,6 +240,10 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, packet_result = Handle_QSetDisableASLR (packet); break; + case StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError: + packet_result = Handle_QSetDetachOnError (packet); + break; + case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN: packet_result = Handle_QSetSTDIN (packet); break; @@ -234,6 +276,26 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, packet_result = Handle_qPlatform_shell (packet); break; + case StringExtractorGDBRemote::eServerPacketType_C: + packet_result = Handle_C (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_c: + packet_result = Handle_c (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_vCont: + packet_result = Handle_vCont (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_vCont_actions: + packet_result = Handle_vCont_actions (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_stop_reason: // ? + packet_result = Handle_stop_reason (packet); + break; + case StringExtractorGDBRemote::eServerPacketType_vFile_open: packet_result = Handle_vFile_Open (packet); break; @@ -277,6 +339,96 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: packet_result = Handle_vFile_unlink (packet); break; + + case StringExtractorGDBRemote::eServerPacketType_qRegisterInfo: + packet_result = Handle_qRegisterInfo (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qfThreadInfo: + packet_result = Handle_qfThreadInfo (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qsThreadInfo: + packet_result = Handle_qsThreadInfo (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_p: + packet_result = Handle_p (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_P: + packet_result = Handle_P (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_H: + packet_result = Handle_H (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_m: + packet_result = Handle_m (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_M: + packet_result = Handle_M (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported: + packet_result = Handle_qMemoryRegionInfoSupported (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo: + packet_result = Handle_qMemoryRegionInfo (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_interrupt: + if (IsGdbServer ()) + packet_result = Handle_interrupt (packet); + else + { + error.SetErrorString("interrupt received"); + interrupt = true; + } + break; + + case StringExtractorGDBRemote::eServerPacketType_Z: + packet_result = Handle_Z (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_z: + packet_result = Handle_z (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_s: + packet_result = Handle_s (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qSupported: + packet_result = Handle_qSupported (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported: + packet_result = Handle_QThreadSuffixSupported (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply: + packet_result = Handle_QListThreadsInStopReply (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read: + packet_result = Handle_qXfer_auxv_read (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState: + packet_result = Handle_QSaveRegisterState (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState: + packet_result = Handle_QRestoreRegisterState (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_vAttach: + packet_result = Handle_vAttach (packet); + break; } } else @@ -291,7 +443,12 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, error.SetErrorString("timeout"); } } - return packet_result == PacketResult::Success; + + // Check if anything occurred that would force us to want to exit. + if (m_exit_now) + quit = true; + + return packet_result; } lldb_private::Error @@ -314,6 +471,96 @@ GDBRemoteCommunicationServer::SetLaunchFlags (unsigned int launch_flags) lldb_private::Error GDBRemoteCommunicationServer::LaunchProcess () { + // FIXME This looks an awful lot like we could override this in + // derived classes, one for lldb-platform, the other for lldb-gdbserver. + if (IsGdbServer ()) + return LaunchDebugServerProcess (); + else + return LaunchPlatformProcess (); +} + +lldb_private::Error +GDBRemoteCommunicationServer::LaunchDebugServerProcess () +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) + return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); + + lldb_private::Error error; + { + Mutex::Locker locker (m_debugged_process_mutex); + assert (!m_debugged_process_sp && "lldb-gdbserver creating debugged process but one already exists"); + error = m_platform_sp->LaunchNativeProcess ( + m_process_launch_info, + *this, + m_debugged_process_sp); + } + + if (!error.Success ()) + { + fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); + return error; + } + + // Setup stdout/stderr mapping from inferior. + auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); + if (terminal_fd >= 0) + { + if (log) + log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); + error = SetSTDIOFileDescriptor (terminal_fd); + if (error.Fail ()) + return error; + } + else + { + if (log) + log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); + } + + printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID ()); + + // Add to list of spawned processes. + lldb::pid_t pid; + if ((pid = m_process_launch_info.GetProcessID ()) != LLDB_INVALID_PROCESS_ID) + { + // add to spawned pids + { + Mutex::Locker locker (m_spawned_pids_mutex); + // On an lldb-gdbserver, we would expect there to be only one. + assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed"); + m_spawned_pids.insert (pid); + } + } + + if (error.Success ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s beginning check to wait for launched application to hit first stop", __FUNCTION__); + + int iteration = 0; + // Wait for the process to hit its first stop state. + while (!StateIsStoppedState (m_debugged_process_sp->GetState (), false)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s waiting for launched process to hit first stop (%d)...", __FUNCTION__, iteration++); + + // FIXME use a finer granularity. + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s launched application has hit first stop", __FUNCTION__); + + } + + return error; +} + +lldb_private::Error +GDBRemoteCommunicationServer::LaunchPlatformProcess () +{ if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); @@ -337,13 +584,571 @@ GDBRemoteCommunicationServer::LaunchProcess () lldb::pid_t pid; if ( (pid = m_process_launch_info.GetProcessID()) != LLDB_INVALID_PROCESS_ID ) { + // add to spawned pids + { + Mutex::Locker locker (m_spawned_pids_mutex); + m_spawned_pids.insert(pid); + } + } + + return error; +} + +lldb_private::Error +GDBRemoteCommunicationServer::AttachToProcess (lldb::pid_t pid) +{ + Error error; + + if (!IsGdbServer ()) + { + error.SetErrorString("cannot AttachToProcess () unless process is lldb-gdbserver"); + return error; + } + + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64, __FUNCTION__, pid); + + // Scope for mutex locker. + { + // Before we try to attach, make sure we aren't already monitoring something else. + Mutex::Locker locker (m_spawned_pids_mutex); + if (!m_spawned_pids.empty ()) + { + error.SetErrorStringWithFormat ("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, *m_spawned_pids.begin()); + return error; + } + + // Try to attach. + error = m_platform_sp->AttachNativeProcess (pid, *this, m_debugged_process_sp); + if (!error.Success ()) + { + fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ()); + return error; + } + + // Setup stdout/stderr mapping from inferior. + auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); + if (terminal_fd >= 0) + { + if (log) + log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); + error = SetSTDIOFileDescriptor (terminal_fd); + if (error.Fail ()) + return error; + } + else + { + if (log) + log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); + } + + printf ("Attached to process %" PRIu64 "...\n", pid); + + // Add to list of spawned processes. + assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed"); + m_spawned_pids.insert (pid); + + return error; + } +} + +void +GDBRemoteCommunicationServer::InitializeDelegate (lldb_private::NativeProcessProtocol *process) +{ + assert (process && "process cannot be NULL"); + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", current state: %s", + __FUNCTION__, + process->GetID (), + StateAsCString (process->GetState ())); + } +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendWResponse (lldb_private::NativeProcessProtocol *process) +{ + assert (process && "process cannot be NULL"); + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // send W notification + ExitType exit_type = ExitType::eExitTypeInvalid; + int return_code = 0; + std::string exit_description; + + const bool got_exit_info = process->GetExitStatus (&exit_type, &return_code, exit_description); + if (!got_exit_info) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", failed to retrieve process exit status", __FUNCTION__, process->GetID ()); + + StreamGDBRemote response; + response.PutChar ('E'); + response.PutHex8 (GDBRemoteServerError::eErrorExitStatus); + return SendPacketNoLock(response.GetData(), response.GetSize()); + } + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", returning exit type %d, return code %d [%s]", __FUNCTION__, process->GetID (), exit_type, return_code, exit_description.c_str ()); + + StreamGDBRemote response; + + char return_type_code; + switch (exit_type) + { + case ExitType::eExitTypeExit: return_type_code = 'W'; break; + case ExitType::eExitTypeSignal: return_type_code = 'X'; break; + case ExitType::eExitTypeStop: return_type_code = 'S'; break; + + case ExitType::eExitTypeInvalid: + default: return_type_code = 'E'; break; + } + response.PutChar (return_type_code); + + // POSIX exit status limited to unsigned 8 bits. + response.PutHex8 (return_code); + + return SendPacketNoLock(response.GetData(), response.GetSize()); + } +} + +static void +AppendHexValue (StreamString &response, const uint8_t* buf, uint32_t buf_size, bool swap) +{ + int64_t i; + if (swap) + { + for (i = buf_size-1; i >= 0; i--) + response.PutHex8 (buf[i]); + } + else + { + for (i = 0; i < buf_size; i++) + response.PutHex8 (buf[i]); + } +} + +static void +WriteRegisterValueInHexFixedWidth (StreamString &response, + NativeRegisterContextSP ®_ctx_sp, + const RegisterInfo ®_info, + const RegisterValue *reg_value_p) +{ + RegisterValue reg_value; + if (!reg_value_p) + { + Error error = reg_ctx_sp->ReadRegister (®_info, reg_value); + if (error.Success ()) + reg_value_p = ®_value; + // else log. + } + + if (reg_value_p) + { + AppendHexValue (response, (const uint8_t*) reg_value_p->GetBytes (), reg_value_p->GetByteSize (), false); + } + else + { + // Zero-out any unreadable values. + if (reg_info.byte_size > 0) + { + std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0'); + AppendHexValue (response, zeros.data(), zeros.size(), false); + } + } +} + +// WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value); + + +static void +WriteGdbRegnumWithFixedWidthHexRegisterValue (StreamString &response, + NativeRegisterContextSP ®_ctx_sp, + const RegisterInfo ®_info, + const RegisterValue ®_value) +{ + // Output the register number as 'NN:VVVVVVVV;' where NN is a 2 bytes HEX + // gdb register number, and VVVVVVVV is the correct number of hex bytes + // as ASCII for the register value. + if (reg_info.kinds[eRegisterKindGDB] == LLDB_INVALID_REGNUM) + return; + + response.Printf ("%.02x:", reg_info.kinds[eRegisterKindGDB]); + WriteRegisterValueInHexFixedWidth (response, reg_ctx_sp, reg_info, ®_value); + response.PutChar (';'); +} + + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendStopReplyPacketForThread (lldb::tid_t tid) +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + + // Ensure we're llgs. + if (!IsGdbServer ()) + { + // Only supported on llgs + return SendUnimplementedResponse (""); + } + + // Ensure we have a debugged process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse (50); + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s preparing packet for pid %" PRIu64 " tid %" PRIu64, + __FUNCTION__, m_debugged_process_sp->GetID (), tid); + + // Ensure we can get info on the given thread. + NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); + if (!thread_sp) + return SendErrorResponse (51); + + // Grab the reason this thread stopped. + struct ThreadStopInfo tid_stop_info; + if (!thread_sp->GetStopReason (tid_stop_info)) + return SendErrorResponse (52); + + const bool did_exec = tid_stop_info.reason == eStopReasonExec; + // FIXME implement register handling for exec'd inferiors. + // if (did_exec) + // { + // const bool force = true; + // InitializeRegisters(force); + // } + + StreamString response; + // Output the T packet with the thread + response.PutChar ('T'); + int signum = tid_stop_info.details.signal.signo; + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64, + __FUNCTION__, + m_debugged_process_sp->GetID (), + tid, + signum, + tid_stop_info.reason, + tid_stop_info.details.exception.type); + } + + switch (tid_stop_info.reason) + { + case eStopReasonSignal: + case eStopReasonException: + signum = thread_sp->TranslateStopInfoToGdbSignal (tid_stop_info); + break; + default: + signum = 0; + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " has stop reason %d, using signo = 0 in stop reply response", + __FUNCTION__, + m_debugged_process_sp->GetID (), + tid, + tid_stop_info.reason); + } + break; + } + + // Print the signal number. + response.PutHex8 (signum & 0xff); + + // Include the tid. + response.Printf ("thread:%" PRIx64 ";", tid); + + // Include the thread name if there is one. + const char *thread_name = thread_sp->GetName (); + if (thread_name && thread_name[0]) + { + size_t thread_name_len = strlen(thread_name); + + if (::strcspn (thread_name, "$#+-;:") == thread_name_len) + { + response.PutCString ("name:"); + response.PutCString (thread_name); + } + else + { + // The thread name contains special chars, send as hex bytes. + response.PutCString ("hexname:"); + response.PutCStringAsRawHex8 (thread_name); + } + response.PutChar (';'); + } + + // FIXME look for analog + // thread_identifier_info_data_t thread_ident_info; + // if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info)) + // { + // if (thread_ident_info.dispatch_qaddr != 0) + // ostrm << std::hex << "qaddr:" << thread_ident_info.dispatch_qaddr << ';'; + // } + + // If a 'QListThreadsInStopReply' was sent to enable this feature, we + // will send all thread IDs back in the "threads" key whose value is + // a list of hex thread IDs separated by commas: + // "threads:10a,10b,10c;" + // This will save the debugger from having to send a pair of qfThreadInfo + // and qsThreadInfo packets, but it also might take a lot of room in the + // stop reply packet, so it must be enabled only on systems where there + // are no limits on packet lengths. + if (m_list_threads_in_stop_reply) + { + response.PutCString ("threads:"); + + uint32_t thread_index = 0; + NativeThreadProtocolSP listed_thread_sp; + for (listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); listed_thread_sp; ++thread_index, listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) + { + if (thread_index > 0) + response.PutChar (','); + response.Printf ("%" PRIx64, listed_thread_sp->GetID ()); + } + response.PutChar (';'); + } + + // + // Expedite registers. + // + + // Grab the register context. + NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext (); + if (reg_ctx_sp) + { + // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers. + const RegisterSet *reg_set_p; + if (reg_ctx_sp->GetRegisterSetCount () > 0 && ((reg_set_p = reg_ctx_sp->GetRegisterSet (0)) != nullptr)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s expediting registers from set '%s' (registers set count: %zu)", __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", reg_set_p->num_registers); + + for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) + { + const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex (*reg_num_p); + if (reg_info_p == nullptr) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to get register info for register set '%s', register index %" PRIu32, __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", *reg_num_p); + } + else if (reg_info_p->value_regs == nullptr) + { + // Only expediate registers that are not contained in other registers. + RegisterValue reg_value; + Error error = reg_ctx_sp->ReadRegister (reg_info_p, reg_value); + if (error.Success ()) + WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value); + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, reg_info_p->name ? reg_info_p->name : "<unnamed-register>", *reg_num_p, error.AsCString ()); + + } + } + } + } + } + + if (did_exec) + { + response.PutCString ("reason:exec;"); + } + else if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) + { + response.PutCString ("metype:"); + response.PutHex64 (tid_stop_info.details.exception.type); + response.PutCString (";mecount:"); + response.PutHex32 (tid_stop_info.details.exception.data_count); + response.PutChar (';'); + + for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) + { + response.PutCString ("medata:"); + response.PutHex64 (tid_stop_info.details.exception.data[i]); + response.PutChar (';'); + } + } + + return SendPacketNoLock (response.GetData(), response.GetSize()); +} + +void +GDBRemoteCommunicationServer::HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process) +{ + assert (process && "process cannot be NULL"); + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); + + // Send the exit result, and don't flush output. + // Note: flushing output here would join the inferior stdio reflection thread, which + // would gunk up the waitpid monitor thread that is calling this. + PacketResult result = SendStopReasonForState (StateType::eStateExited, false); + if (result != PacketResult::Success) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); + } + + // Remove the process from the list of spawned pids. + { Mutex::Locker locker (m_spawned_pids_mutex); - m_spawned_pids.insert(pid); + if (m_spawned_pids.erase (process->GetID ()) < 1) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to remove PID %" PRIu64 " from the spawned pids list", __FUNCTION__, process->GetID ()); + + } } + // FIXME can't do this yet - since process state propagation is currently + // synchronous, it is running off the NativeProcessProtocol's innards and + // will tear down the NPP while it still has code to execute. +#if 0 + // Clear the NativeProcessProtocol pointer. + { + Mutex::Locker locker (m_debugged_process_mutex); + m_debugged_process_sp.reset(); + } +#endif + + // Close the pipe to the inferior terminal i/o if we launched it + // and set one up. Otherwise, 'k' and its flush of stdio could + // end up waiting on a thread join that will never end. Consider + // adding a timeout to the connection thread join call so we + // can avoid that scenario altogether. + MaybeCloseInferiorTerminalConnection (); + + // We are ready to exit the debug monitor. + m_exit_now = true; +} + +void +GDBRemoteCommunicationServer::HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process) +{ + assert (process && "process cannot be NULL"); + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); + + // Send the stop reason unless this is the stop after the + // launch or attach. + switch (m_inferior_prev_state) + { + case eStateLaunching: + case eStateAttaching: + // Don't send anything per debugserver behavior. + break; + default: + // In all other cases, send the stop reason. + PacketResult result = SendStopReasonForState (StateType::eStateStopped, false); + if (result != PacketResult::Success) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); + } + break; + } +} + +void +GDBRemoteCommunicationServer::ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state) +{ + assert (process && "process cannot be NULL"); + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", state: %s", + __FUNCTION__, + process->GetID (), + StateAsCString (state)); + } + + switch (state) + { + case StateType::eStateExited: + HandleInferiorState_Exited (process); + break; + + case StateType::eStateStopped: + HandleInferiorState_Stopped (process); + break; + + default: + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s didn't handle state change for pid %" PRIu64 ", new state: %s", + __FUNCTION__, + process->GetID (), + StateAsCString (state)); + } + break; + } + + // Remember the previous state reported to us. + m_inferior_prev_state = state; +} + +void +GDBRemoteCommunicationServer::DidExec (NativeProcessProtocol *process) +{ + ClearProcessSpecificData (); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendONotification (const char *buffer, uint32_t len) +{ + if ((buffer == nullptr) || (len == 0)) + { + // Nothing to send. + return PacketResult::Success; + } + + StreamString response; + response.PutChar ('O'); + response.PutBytesAsRawHex8 (buffer, len); + + return SendPacketNoLock (response.GetData (), response.GetSize ()); +} + +lldb_private::Error +GDBRemoteCommunicationServer::SetSTDIOFileDescriptor (int fd) +{ + Error error; + + // Set up the Read Thread for reading/handling process I/O + std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true)); + if (!conn_up) + { + error.SetErrorString ("failed to create ConnectionFileDescriptor"); + return error; + } + + m_stdio_communication.SetConnection (conn_up.release()); + if (!m_stdio_communication.IsConnected ()) + { + error.SetErrorString ("failed to set connection for inferior I/O communication"); + return error; + } + + m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this); + m_stdio_communication.StartReadThread(); + return error; } +void +GDBRemoteCommunicationServer::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len) +{ + GDBRemoteCommunicationServer *server = reinterpret_cast<GDBRemoteCommunicationServer*> (baton); + static_cast<void> (server->SendONotification (static_cast<const char *>(src), src_len)); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *) { @@ -351,6 +1156,7 @@ GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *) return SendPacketNoLock ("", 0); } + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err) { @@ -360,6 +1166,14 @@ GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err) return SendPacketNoLock (packet, packet_len); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendIllFormedResponse (const StringExtractorGDBRemote &failed_packet, const char *message) +{ + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", __FUNCTION__, failed_packet.GetStringRef ().c_str (), message ? message : ""); + return SendErrorResponse (0x03); +} GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendOKResponse () @@ -380,10 +1194,10 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00 - ArchSpec host_arch (Host::GetArchitecture ()); + ArchSpec host_arch(HostInfo::GetArchitecture()); const llvm::Triple &host_triple = host_arch.GetTriple(); response.PutCString("triple:"); - response.PutCStringAsRawHex8(host_triple.getTriple().c_str()); + response.PutCString(host_triple.getTriple().c_str()); response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize()); const char* distribution_id = host_arch.GetDistributionId ().AsCString (); @@ -394,6 +1208,8 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet response.PutCString(";"); } + // Only send out MachO info when lldb-platform/llgs is running on a MachO host. +#if defined(__APPLE__) uint32_t cpu = host_arch.GetMachOCPUType(); uint32_t sub = host_arch.GetMachOCPUSubType(); if (cpu != LLDB_INVALID_CPUTYPE) @@ -405,6 +1221,9 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. else response.Printf("watchpoint_exceptions_received:after;"); +#else + response.Printf("watchpoint_exceptions_received:after;"); +#endif switch (lldb::endian::InlHostByteOrder()) { @@ -417,7 +1236,7 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet uint32_t major = UINT32_MAX; uint32_t minor = UINT32_MAX; uint32_t update = UINT32_MAX; - if (Host::GetOSVersion (major, minor, update)) + if (HostInfo::GetOSVersion(major, minor, update)) { if (major != UINT32_MAX) { @@ -433,39 +1252,41 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet } std::string s; - if (Host::GetOSBuildString (s)) +#if !defined(__linux__) + if (HostInfo::GetOSBuildString(s)) { response.PutCString ("os_build:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } - if (Host::GetOSKernelDescription (s)) + if (HostInfo::GetOSKernelDescription(s)) { response.PutCString ("os_kernel:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } +#endif + #if defined(__APPLE__) -#if defined(__arm__) +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) // For iOS devices, we are connected through a USB Mux so we never pretend // to actually have a hostname as far as the remote lldb that is connecting // to this lldb-platform is concerned response.PutCString ("hostname:"); - response.PutCStringAsRawHex8("localhost"); + response.PutCStringAsRawHex8("127.0.0.1"); response.PutChar(';'); -#else // #if defined(__arm__) - if (Host::GetHostname (s)) +#else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + if (HostInfo::GetHostname(s)) { response.PutCString ("hostname:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } - -#endif // #if defined(__arm__) +#endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) #else // #if defined(__APPLE__) - if (Host::GetHostname (s)) + if (HostInfo::GetHostname(s)) { response.PutCString ("hostname:"); response.PutCStringAsRawHex8(s.c_str()); @@ -494,11 +1315,105 @@ CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &r { const llvm::Triple &proc_triple = proc_arch.GetTriple(); response.PutCString("triple:"); - response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); + response.PutCString(proc_triple.getTriple().c_str()); response.PutChar(';'); } } +static void +CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info, StreamString &response) +{ + response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;", + proc_info.GetProcessID(), + proc_info.GetParentProcessID(), + proc_info.GetUserID(), + proc_info.GetGroupID(), + proc_info.GetEffectiveUserID(), + proc_info.GetEffectiveGroupID()); + + const ArchSpec &proc_arch = proc_info.GetArchitecture(); + if (proc_arch.IsValid()) + { + const llvm::Triple &proc_triple = proc_arch.GetTriple(); +#if defined(__APPLE__) + // We'll send cputype/cpusubtype. + const uint32_t cpu_type = proc_arch.GetMachOCPUType(); + if (cpu_type != 0) + response.Printf ("cputype:%" PRIx32 ";", cpu_type); + + const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType(); + if (cpu_subtype != 0) + response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype); + + + const std::string vendor = proc_triple.getVendorName (); + if (!vendor.empty ()) + response.Printf ("vendor:%s;", vendor.c_str ()); +#else + // We'll send the triple. + response.Printf ("triple:%s;", proc_triple.getTriple().c_str ()); +#endif + std::string ostype = proc_triple.getOSName (); + // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. + if (proc_triple.getVendor () == llvm::Triple::Apple) + { + switch (proc_triple.getArch ()) + { + case llvm::Triple::arm: + case llvm::Triple::aarch64: + ostype = "ios"; + break; + default: + // No change. + break; + } + } + response.Printf ("ostype:%s;", ostype.c_str ()); + + + switch (proc_arch.GetByteOrder ()) + { + case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break; + case lldb::eByteOrderBig: response.PutCString ("endian:big;"); break; + case lldb::eByteOrderPDP: response.PutCString ("endian:pdp;"); break; + default: + // Nothing. + break; + } + + if (proc_triple.isArch64Bit ()) + response.PutCString ("ptrsize:8;"); + else if (proc_triple.isArch32Bit ()) + response.PutCString ("ptrsize:4;"); + else if (proc_triple.isArch16Bit ()) + response.PutCString ("ptrsize:2;"); + } + +} + + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_qProcessInfo (StringExtractorGDBRemote &packet) +{ + // Only the gdb server handles this. + if (!IsGdbServer ()) + return SendUnimplementedResponse (packet.GetStringRef ().c_str ()); + + // Fail if we don't have a current process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse (68); + + ProcessInstanceInfo proc_info; + if (Host::GetProcessInfo (m_debugged_process_sp->GetID (), proc_info)) + { + StreamString response; + CreateProcessInfoResponse_DebugServerStyle(proc_info, response); + return SendPacketNoLock (response.GetData (), response.GetSize ()); + } + + return SendErrorResponse (1); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet) { @@ -635,19 +1550,21 @@ GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &pa GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet) { +#if !defined(LLDB_DISABLE_POSIX) // Packet format: "qUserName:%i" where %i is the uid packet.SetFilePos(::strlen ("qUserName:")); uint32_t uid = packet.GetU32 (UINT32_MAX); if (uid != UINT32_MAX) { std::string name; - if (Host::GetUserName (uid, name)) + if (HostInfo::LookupUserName(uid, name)) { StreamString response; response.PutCStringAsRawHex8 (name.c_str()); return SendPacketNoLock (response.GetData(), response.GetSize()); } } +#endif return SendErrorResponse (5); } @@ -655,19 +1572,21 @@ GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet) { +#if !defined(LLDB_DISABLE_POSIX) // Packet format: "qGroupName:%i" where %i is the gid packet.SetFilePos(::strlen ("qGroupName:")); uint32_t gid = packet.GetU32 (UINT32_MAX); if (gid != UINT32_MAX) { std::string name; - if (Host::GetGroupName (gid, name)) + if (HostInfo::LookupGroupName(gid, name)) { StreamString response; response.PutCStringAsRawHex8 (name.c_str()); return SendPacketNoLock (response.GetData(), response.GetSize()); } } +#endif return SendErrorResponse (6); } @@ -708,27 +1627,6 @@ GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packe return SendErrorResponse (7); } - -static void * -AcceptPortFromInferior (void *arg) -{ - const char *connect_url = (const char *)arg; - ConnectionFileDescriptor file_conn; - Error error; - if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess) - { - char pid_str[256]; - ::memset (pid_str, 0, sizeof(pid_str)); - ConnectionStatus status; - const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), 0, status, NULL); - if (pid_str_len > 0) - { - int pid = atoi (pid_str); - return (void *)(intptr_t)pid; - } - } - return NULL; -} // //static bool //WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds) @@ -772,6 +1670,9 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) // separated hex encoded argument value list, but we will stay true to the // documented version of the 'A' packet here... + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + int actual_arg_index = 0; + packet.SetFilePos(1); // Skip the 'A' bool success = true; while (success && packet.GetBytesLeft() > 0) @@ -788,7 +1689,7 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) success = false; else { - // Decode the argument index. We ignore this really becuase + // Decode the argument index. We ignore this really because // who would really send down the arguments in a random order??? const uint32_t arg_idx = packet.GetU32(UINT32_MAX); if (arg_idx == UINT32_MAX) @@ -804,11 +1705,11 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) // back into a UTF8 string and make sure the length // matches the one supplied in the packet std::string arg; - if (packet.GetHexByteString(arg) != (arg_len / 2)) + if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2)) success = false; else { - // If there are any bytes lft + // If there are any bytes left if (packet.GetBytesLeft()) { if (packet.GetChar() != ',') @@ -820,6 +1721,9 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) if (arg_idx == 0) m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false); m_process_launch_info.GetArguments().AppendArgument(arg.c_str()); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ()); + ++actual_arg_index; } } } @@ -830,15 +1734,20 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) if (success) { - // FIXME: remove linux restriction once eLaunchFlagDebug is supported -#if !defined (__linux__) - m_process_launch_info.GetFlags().Set (eLaunchFlagDebug); -#endif m_process_launch_error = LaunchProcess (); if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { return SendOKResponse (); } + else + { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunicationServer::%s failed to launch exe: %s", + __FUNCTION__, + m_process_launch_error.AsCString()); + + } } return SendErrorResponse (8); } @@ -846,22 +1755,51 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet) { - lldb::pid_t pid = m_process_launch_info.GetProcessID(); StreamString response; - response.Printf("QC%" PRIx64, pid); - if (m_is_platform) + + if (IsGdbServer ()) + { + // Fail if we don't have a current process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse (68); + + // Make sure we set the current thread so g and p packets return + // the data the gdb will expect. + lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); + SetCurrentThreadID (tid); + + NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread (); + if (!thread_sp) + return SendErrorResponse (69); + + response.Printf ("QC%" PRIx64, thread_sp->GetID ()); + } + else { - // If we launch a process and this GDB server is acting as a platform, - // then we need to clear the process launch state so we can start - // launching another process. In order to launch a process a bunch or - // packets need to be sent: environment packets, working directory, - // disable ASLR, and many more settings. When we launch a process we - // then need to know when to clear this information. Currently we are - // selecting the 'qC' packet as that packet which seems to make the most - // sense. - if (pid != LLDB_INVALID_PROCESS_ID) + // NOTE: lldb should now be using qProcessInfo for process IDs. This path here + // should not be used. It is reporting process id instead of thread id. The + // correct answer doesn't seem to make much sense for lldb-platform. + // CONSIDER: flip to "unsupported". + lldb::pid_t pid = m_process_launch_info.GetProcessID(); + response.Printf("QC%" PRIx64, pid); + + // this should always be platform here + assert (m_is_platform && "this code path should only be traversed for lldb-platform"); + + if (m_is_platform) { - m_process_launch_info.Clear(); + // If we launch a process and this GDB server is acting as a platform, + // then we need to clear the process launch state so we can start + // launching another process. In order to launch a process a bunch or + // packets need to be sent: environment packets, working directory, + // disable ASLR, and many more settings. When we launch a process we + // then need to know when to clear this information. Currently we are + // selecting the 'qC' packet as that packet which seems to make the most + // sense. + if (pid != LLDB_INVALID_PROCESS_ID) + { + m_process_launch_info.Clear(); + } } } return SendPacketNoLock (response.GetData(), response.GetSize()); @@ -912,17 +1850,21 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote #ifdef _WIN32 return SendErrorResponse(9); #else + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + // Spawn a local debugserver as a platform so we can then attach or launch // a process... if (m_is_platform) { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() called", __FUNCTION__); + // Sleep and wait a bit for debugserver to start to listen... ConnectionFileDescriptor file_conn; - Error error; std::string hostname; // TODO: /tmp/ should not be hardcoded. User might want to override /tmp - // with the TMPDIR environnement variable + // with the TMPDIR environment variable packet.SetFilePos(::strlen ("qLaunchGDBServer;")); std::string name; std::string value; @@ -940,53 +1882,57 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). - if (error.Success()) - { - // Spawn a debugserver and try to get the port it listens to. - ProcessLaunchInfo debugserver_launch_info; - if (hostname.empty()) - hostname = "localhost"; - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port); + // Spawn a debugserver and try to get the port it listens to. + ProcessLaunchInfo debugserver_launch_info; + if (hostname.empty()) + hostname = "127.0.0.1"; + if (log) + log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port); - debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); - - error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(), - port, - debugserver_launch_info, - port); + debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); - lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); + Error error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(), + port, + debugserver_launch_info, + port); + lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - { - Mutex::Locker locker (m_spawned_pids_mutex); - m_spawned_pids.insert(debugserver_pid); - if (port > 0) - AssociatePortWithProcess(port, debugserver_pid); - } - else - { - if (port > 0) - FreePort (port); - } - if (error.Success()) - { - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - assert (response_len < sizeof(response)); - PacketResult packet_result = SendPacketNoLock (response, response_len); + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + { + Mutex::Locker locker (m_spawned_pids_mutex); + m_spawned_pids.insert(debugserver_pid); + if (port > 0) + AssociatePortWithProcess(port, debugserver_pid); + } + else + { + if (port > 0) + FreePort (port); + } - if (packet_result != PacketResult::Success) - { - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill (debugserver_pid, SIGINT); - } - return packet_result; + if (error.Success()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); + + char response[256]; + const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); + assert (response_len < (int)sizeof(response)); + PacketResult packet_result = SendPacketNoLock (response, response_len); + + if (packet_result != PacketResult::Success) + { + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + ::kill (debugserver_pid, SIGINT); } + return packet_result; + } + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); } } return SendErrorResponse (9); @@ -1027,7 +1973,7 @@ GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid) return true; } - // the launched process still lives. Now try killling it again, + // the launched process still lives. Now try killing it again, // this time with an unblockable signal. Host::Kill (pid, SIGKILL); @@ -1107,8 +2053,11 @@ GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet) } } - // TODO figure out how to shut down gracefully at this point - return SendOKResponse (); + FlushInferiorOutput (); + + // No OK response for kill packet. + // return SendOKResponse (); + return PacketResult::Success; } GDBRemoteCommunication::PacketResult @@ -1223,7 +2172,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDIN:")); - ProcessLaunchInfo::FileAction file_action; + FileAction file_action; std::string path; packet.GetHexByteString(path); const bool read = false; @@ -1240,7 +2189,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDOUT:")); - ProcessLaunchInfo::FileAction file_action; + FileAction file_action; std::string path; packet.GetHexByteString(path); const bool read = true; @@ -1257,7 +2206,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDERR:")); - ProcessLaunchInfo::FileAction file_action; + FileAction file_action; std::string path; packet.GetHexByteString(path); const bool read = true; @@ -1271,6 +2220,288 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe } GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_C (StringExtractorGDBRemote &packet) +{ + if (!IsGdbServer ()) + return SendUnimplementedResponse (packet.GetStringRef().c_str()); + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); + + // Ensure we have a native process. + if (!m_debugged_process_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__); + return SendErrorResponse (0x36); + } + + // Pull out the signal number. + packet.SetFilePos (::strlen ("C")); + if (packet.GetBytesLeft () < 1) + { + // Shouldn't be using a C without a signal. + return SendIllFormedResponse (packet, "C packet specified without signal."); + } + const uint32_t signo = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (signo == std::numeric_limits<uint32_t>::max ()) + return SendIllFormedResponse (packet, "failed to parse signal number"); + + // Handle optional continue address. + if (packet.GetBytesLeft () > 0) + { + // FIXME add continue at address support for $C{signo}[;{continue-address}]. + if (*packet.Peek () == ';') + return SendUnimplementedResponse (packet.GetStringRef().c_str()); + else + return SendIllFormedResponse (packet, "unexpected content after $C{signal-number}"); + } + + lldb_private::ResumeActionList resume_actions (StateType::eStateRunning, 0); + Error error; + + // We have two branches: what to do if a continue thread is specified (in which case we target + // sending the signal to that thread), or when we don't have a continue thread set (in which + // case we send a signal to the process). + + // TODO discuss with Greg Clayton, make sure this makes sense. + + lldb::tid_t signal_tid = GetContinueThreadID (); + if (signal_tid != LLDB_INVALID_THREAD_ID) + { + // The resume action for the continue thread (or all threads if a continue thread is not set). + lldb_private::ResumeAction action = { GetContinueThreadID (), StateType::eStateRunning, static_cast<int> (signo) }; + + // Add the action for the continue thread (or all threads when the continue thread isn't present). + resume_actions.Append (action); + } + else + { + // Send the signal to the process since we weren't targeting a specific continue thread with the signal. + error = m_debugged_process_sp->Signal (signo); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to send signal for process %" PRIu64 ": %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + error.AsCString ()); + + return SendErrorResponse (0x52); + } + } + + // Resume the threads. + error = m_debugged_process_sp->Resume (resume_actions); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to resume threads for process %" PRIu64 ": %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + error.AsCString ()); + + return SendErrorResponse (0x38); + } + + // Don't send an "OK" packet; response is the stopped/exited message. + return PacketResult::Success; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment) +{ + if (!IsGdbServer ()) + return SendUnimplementedResponse (packet.GetStringRef().c_str()); + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__); + + // We reuse this method in vCont - don't double adjust the file position. + if (!skip_file_pos_adjustment) + packet.SetFilePos (::strlen ("c")); + + // For now just support all continue. + const bool has_continue_address = (packet.GetBytesLeft () > 0); + if (has_continue_address) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s not implemented for c{address} variant [%s remains]", __FUNCTION__, packet.Peek ()); + return SendUnimplementedResponse (packet.GetStringRef().c_str()); + } + + // Ensure we have a native process. + if (!m_debugged_process_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__); + return SendErrorResponse (0x36); + } + + // Build the ResumeActionList + lldb_private::ResumeActionList actions (StateType::eStateRunning, 0); + + Error error = m_debugged_process_sp->Resume (actions); + if (error.Fail ()) + { + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s c failed for process %" PRIu64 ": %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + error.AsCString ()); + } + return SendErrorResponse (GDBRemoteServerError::eErrorResume); + } + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + + // No response required from continue. + return PacketResult::Success; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_vCont_actions (StringExtractorGDBRemote &packet) +{ + if (!IsGdbServer ()) + { + // only llgs supports $vCont. + return SendUnimplementedResponse (packet.GetStringRef().c_str()); + } + + // We handle $vCont messages for c. + // TODO add C, s and S. + StreamString response; + response.Printf("vCont;c;C;s;S"); + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_vCont (StringExtractorGDBRemote &packet) +{ + if (!IsGdbServer ()) + { + // only llgs supports $vCont + return SendUnimplementedResponse (packet.GetStringRef().c_str()); + } + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s handling vCont packet", __FUNCTION__); + + packet.SetFilePos (::strlen ("vCont")); + + // Check if this is all continue (no options or ";c"). + if (!packet.GetBytesLeft () || (::strcmp (packet.Peek (), ";c") == 0)) + { + // Move the packet past the ";c". + if (packet.GetBytesLeft ()) + packet.SetFilePos (packet.GetFilePos () + ::strlen (";c")); + + const bool skip_file_pos_adjustment = true; + return Handle_c (packet, skip_file_pos_adjustment); + } + else if (::strcmp (packet.Peek (), ";s") == 0) + { + // Move past the ';', then do a simple 's'. + packet.SetFilePos (packet.GetFilePos () + 1); + return Handle_s (packet); + } + + // Ensure we have a native process. + if (!m_debugged_process_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__); + return SendErrorResponse (0x36); + } + + ResumeActionList thread_actions; + + while (packet.GetBytesLeft () && *packet.Peek () == ';') + { + // Skip the semi-colon. + packet.GetChar (); + + // Build up the thread action. + ResumeAction thread_action; + thread_action.tid = LLDB_INVALID_THREAD_ID; + thread_action.state = eStateInvalid; + thread_action.signal = 0; + + const char action = packet.GetChar (); + switch (action) + { + case 'C': + thread_action.signal = packet.GetHexMaxU32 (false, 0); + if (thread_action.signal == 0) + return SendIllFormedResponse (packet, "Could not parse signal in vCont packet C action"); + // Fall through to next case... + + case 'c': + // Continue + thread_action.state = eStateRunning; + break; + + case 'S': + thread_action.signal = packet.GetHexMaxU32 (false, 0); + if (thread_action.signal == 0) + return SendIllFormedResponse (packet, "Could not parse signal in vCont packet S action"); + // Fall through to next case... + + case 's': + // Step + thread_action.state = eStateStepping; + break; + + default: + return SendIllFormedResponse (packet, "Unsupported vCont action"); + break; + } + + // Parse out optional :{thread-id} value. + if (packet.GetBytesLeft () && (*packet.Peek () == ':')) + { + // Consume the separator. + packet.GetChar (); + + thread_action.tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); + if (thread_action.tid == LLDB_INVALID_THREAD_ID) + return SendIllFormedResponse (packet, "Could not parse thread number in vCont packet"); + } + + thread_actions.Append (thread_action); + } + + // If a default action for all other threads wasn't mentioned + // then we should stop the threads. + thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0); + + Error error = m_debugged_process_sp->Resume (thread_actions); + if (error.Fail ()) + { + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s vCont failed for process %" PRIu64 ": %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + error.AsCString ()); + } + return SendErrorResponse (GDBRemoteServerError::eErrorResume); + } + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + + // No response required from vCont. + return PacketResult::Success; +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet) { // Send response first before changing m_send_acks to we ack this packet @@ -1288,7 +2519,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote & { std::string path; packet.GetHexByteString(path); - Error error = Host::MakeDirectory(path.c_str(),mode); + Error error = FileSystem::MakeDirectory(path.c_str(), mode); if (error.Success()) return SendPacketNoLock ("OK", 2); else @@ -1307,7 +2538,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote & { std::string path; packet.GetHexByteString(path); - Error error = Host::SetFilePermissions (path.c_str(), mode); + Error error = FileSystem::SetFilePermissions(path.c_str(), mode); if (error.Success()) return SendPacketNoLock ("OK", 2); else @@ -1457,7 +2688,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packe packet.GetHexByteString(path); if (!path.empty()) { - lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false)); + lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path.c_str(), false)); StreamString response; response.PutChar('F'); response.PutHex64(retcode); @@ -1498,7 +2729,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &pac packet.GetHexByteString(path); if (!path.empty()) { - bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false)); + bool retcode = FileSystem::GetFileExists(FileSpec(path.c_str(), false)); StreamString response; response.PutChar('F'); response.PutChar(','); @@ -1519,7 +2750,7 @@ GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &pa packet.GetHexByteStringTerminatedBy(dst, ','); packet.GetChar(); // Skip ',' char packet.GetHexByteString(src); - Error error = Host::Symlink(src.c_str(), dst.c_str()); + Error error = FileSystem::Symlink(src.c_str(), dst.c_str()); StreamString response; response.Printf("F%u,%u", error.GetError(), error.GetError()); return SendPacketNoLock(response.GetData(), response.GetSize()); @@ -1531,7 +2762,7 @@ GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &pac packet.SetFilePos(::strlen("vFile:unlink:")); std::string path; packet.GetHexByteString(path); - Error error = Host::Unlink(path.c_str()); + Error error = FileSystem::Unlink(path.c_str()); StreamString response; response.Printf("F%u,%u", error.GetError(), error.GetError()); return SendPacketNoLock(response.GetData(), response.GetSize()); @@ -1579,6 +2810,94 @@ GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote & return SendErrorResponse(24); } +void +GDBRemoteCommunicationServer::SetCurrentThreadID (lldb::tid_t tid) +{ + assert (IsGdbServer () && "SetCurrentThreadID() called when not GdbServer code"); + + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s setting current thread id to %" PRIu64, __FUNCTION__, tid); + + m_current_tid = tid; + if (m_debugged_process_sp) + m_debugged_process_sp->SetCurrentThreadID (m_current_tid); +} + +void +GDBRemoteCommunicationServer::SetContinueThreadID (lldb::tid_t tid) +{ + assert (IsGdbServer () && "SetContinueThreadID() called when not GdbServer code"); + + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s setting continue thread id to %" PRIu64, __FUNCTION__, tid); + + m_continue_tid = tid; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_stop_reason (StringExtractorGDBRemote &packet) +{ + // Handle the $? gdbremote command. + if (!IsGdbServer ()) + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_stop_reason() unimplemented"); + + // If no process, indicate error + if (!m_debugged_process_sp) + return SendErrorResponse (02); + + return SendStopReasonForState (m_debugged_process_sp->GetState (), true); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + switch (process_state) + { + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + // NOTE: gdb protocol doc looks like it should return $OK + // when everything is running (i.e. no stopped result). + return PacketResult::Success; // Ignore + + case eStateSuspended: + case eStateStopped: + case eStateCrashed: + { + lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); + // Make sure we set the current thread so g and p packets return + // the data the gdb will expect. + SetCurrentThreadID (tid); + return SendStopReplyPacketForThread (tid); + } + + case eStateInvalid: + case eStateUnloaded: + case eStateExited: + if (flush_on_exit) + FlushInferiorOutput (); + return SendWResponse(m_debugged_process_sp.get()); + + default: + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", current state reporting not handled: %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + StateAsCString (process_state)); + } + break; + } + + return SendErrorResponse (0); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet) { @@ -1595,7 +2914,7 @@ GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet { uint64_t a,b; StreamGDBRemote response; - if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false) + if (FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b) == false) { response.PutCString("F,"); response.PutCString("x"); @@ -1611,3 +2930,1385 @@ GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet return SendErrorResponse(25); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_qRegisterInfo (StringExtractorGDBRemote &packet) +{ + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qRegisterInfo() unimplemented"); + + // Fail if we don't have a current process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse (68); + + // Ensure we have a thread. + NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadAtIndex (0)); + if (!thread_sp) + return SendErrorResponse (69); + + // Get the register context for the first thread. + NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); + if (!reg_context_sp) + return SendErrorResponse (69); + + // Parse out the register number from the request. + packet.SetFilePos (strlen("qRegisterInfo")); + const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (reg_index == std::numeric_limits<uint32_t>::max ()) + return SendErrorResponse (69); + + // Return the end of registers response if we've iterated one past the end of the register set. + if (reg_index >= reg_context_sp->GetRegisterCount ()) + return SendErrorResponse (69); + + const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + return SendErrorResponse (69); + + // Build the reginfos response. + StreamGDBRemote response; + + response.PutCString ("name:"); + response.PutCString (reg_info->name); + response.PutChar (';'); + + if (reg_info->alt_name && reg_info->alt_name[0]) + { + response.PutCString ("alt-name:"); + response.PutCString (reg_info->alt_name); + response.PutChar (';'); + } + + response.Printf ("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset); + + switch (reg_info->encoding) + { + case eEncodingUint: response.PutCString ("encoding:uint;"); break; + case eEncodingSint: response.PutCString ("encoding:sint;"); break; + case eEncodingIEEE754: response.PutCString ("encoding:ieee754;"); break; + case eEncodingVector: response.PutCString ("encoding:vector;"); break; + default: break; + } + + switch (reg_info->format) + { + case eFormatBinary: response.PutCString ("format:binary;"); break; + case eFormatDecimal: response.PutCString ("format:decimal;"); break; + case eFormatHex: response.PutCString ("format:hex;"); break; + case eFormatFloat: response.PutCString ("format:float;"); break; + case eFormatVectorOfSInt8: response.PutCString ("format:vector-sint8;"); break; + case eFormatVectorOfUInt8: response.PutCString ("format:vector-uint8;"); break; + case eFormatVectorOfSInt16: response.PutCString ("format:vector-sint16;"); break; + case eFormatVectorOfUInt16: response.PutCString ("format:vector-uint16;"); break; + case eFormatVectorOfSInt32: response.PutCString ("format:vector-sint32;"); break; + case eFormatVectorOfUInt32: response.PutCString ("format:vector-uint32;"); break; + case eFormatVectorOfFloat32: response.PutCString ("format:vector-float32;"); break; + case eFormatVectorOfUInt128: response.PutCString ("format:vector-uint128;"); break; + default: break; + }; + + const char *const register_set_name = reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index); + if (register_set_name) + { + response.PutCString ("set:"); + response.PutCString (register_set_name); + response.PutChar (';'); + } + + if (reg_info->kinds[RegisterKind::eRegisterKindGCC] != LLDB_INVALID_REGNUM) + response.Printf ("gcc:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindGCC]); + + if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM) + response.Printf ("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]); + + switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric]) + { + case LLDB_REGNUM_GENERIC_PC: response.PutCString("generic:pc;"); break; + case LLDB_REGNUM_GENERIC_SP: response.PutCString("generic:sp;"); break; + case LLDB_REGNUM_GENERIC_FP: response.PutCString("generic:fp;"); break; + case LLDB_REGNUM_GENERIC_RA: response.PutCString("generic:ra;"); break; + case LLDB_REGNUM_GENERIC_FLAGS: response.PutCString("generic:flags;"); break; + case LLDB_REGNUM_GENERIC_ARG1: response.PutCString("generic:arg1;"); break; + case LLDB_REGNUM_GENERIC_ARG2: response.PutCString("generic:arg2;"); break; + case LLDB_REGNUM_GENERIC_ARG3: response.PutCString("generic:arg3;"); break; + case LLDB_REGNUM_GENERIC_ARG4: response.PutCString("generic:arg4;"); break; + case LLDB_REGNUM_GENERIC_ARG5: response.PutCString("generic:arg5;"); break; + case LLDB_REGNUM_GENERIC_ARG6: response.PutCString("generic:arg6;"); break; + case LLDB_REGNUM_GENERIC_ARG7: response.PutCString("generic:arg7;"); break; + case LLDB_REGNUM_GENERIC_ARG8: response.PutCString("generic:arg8;"); break; + default: break; + } + + if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) + { + response.PutCString ("container-regs:"); + int i = 0; + for (const uint32_t *reg_num = reg_info->value_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) + { + if (i > 0) + response.PutChar (','); + response.Printf ("%" PRIx32, *reg_num); + } + response.PutChar (';'); + } + + if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) + { + response.PutCString ("invalidate-regs:"); + int i = 0; + for (const uint32_t *reg_num = reg_info->invalidate_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) + { + if (i > 0) + response.PutChar (','); + response.Printf ("%" PRIx32, *reg_num); + } + response.PutChar (';'); + } + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_qfThreadInfo (StringExtractorGDBRemote &packet) +{ + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qfThreadInfo() unimplemented"); + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Fail if we don't have a current process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() no process (%s), returning OK", __FUNCTION__, m_debugged_process_sp ? "invalid process id" : "null m_debugged_process_sp"); + return SendOKResponse (); + } + + StreamGDBRemote response; + response.PutChar ('m'); + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() starting thread iteration", __FUNCTION__); + + NativeThreadProtocolSP thread_sp; + uint32_t thread_index; + for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); + thread_sp; + ++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() iterated thread %" PRIu32 "(%s, tid=0x%" PRIx64 ")", __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", thread_sp ? thread_sp->GetID () : LLDB_INVALID_THREAD_ID); + if (thread_index > 0) + response.PutChar(','); + response.Printf ("%" PRIx64, thread_sp->GetID ()); + } + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() finished thread iteration", __FUNCTION__); + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_qsThreadInfo (StringExtractorGDBRemote &packet) +{ + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_qsThreadInfo() unimplemented"); + + // FIXME for now we return the full thread list in the initial packet and always do nothing here. + return SendPacketNoLock ("l", 1); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_p (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_p() unimplemented"); + + // Parse out the register number from the request. + packet.SetFilePos (strlen("p")); + const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (reg_index == std::numeric_limits<uint32_t>::max ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); + return SendErrorResponse (0x15); + } + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); + if (!thread_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available", __FUNCTION__); + return SendErrorResponse (0x15); + } + + // Get the thread's register context. + NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); + if (!reg_context_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); + return SendErrorResponse (0x15); + } + + // Return the end of registers response if we've iterated one past the end of the register set. + if (reg_index >= reg_context_sp->GetRegisterCount ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetRegisterCount ()); + return SendErrorResponse (0x15); + } + + const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); + return SendErrorResponse (0x15); + } + + // Build the reginfos response. + StreamGDBRemote response; + + // Retrieve the value + RegisterValue reg_value; + Error error = reg_context_sp->ReadRegister (reg_info, reg_value); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, read of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); + return SendErrorResponse (0x15); + } + + const uint8_t *const data = reinterpret_cast<const uint8_t*> (reg_value.GetBytes ()); + if (!data) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to get data bytes from requested register %" PRIu32, __FUNCTION__, reg_index); + return SendErrorResponse (0x15); + } + + // FIXME flip as needed to get data in big/little endian format for this host. + for (uint32_t i = 0; i < reg_value.GetByteSize (); ++i) + response.PutHex8 (data[i]); + + return SendPacketNoLock (response.GetData (), response.GetSize ()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_P (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_P() unimplemented"); + + // Ensure there is more content. + if (packet.GetBytesLeft () < 1) + return SendIllFormedResponse (packet, "Empty P packet"); + + // Parse out the register number from the request. + packet.SetFilePos (strlen("P")); + const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (reg_index == std::numeric_limits<uint32_t>::max ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); + return SendErrorResponse (0x29); + } + + // Note debugserver would send an E30 here. + if ((packet.GetBytesLeft () < 1) || (packet.GetChar () != '=')) + return SendIllFormedResponse (packet, "P packet missing '=' char after register number"); + + // Get process architecture. + ArchSpec process_arch; + if (!m_debugged_process_sp || !m_debugged_process_sp->GetArchitecture (process_arch)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to retrieve inferior architecture", __FUNCTION__); + return SendErrorResponse (0x49); + } + + // Parse out the value. + const uint64_t raw_value = packet.GetHexMaxU64 (process_arch.GetByteOrder () == lldb::eByteOrderLittle, std::numeric_limits<uint64_t>::max ()); + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); + if (!thread_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available (thread index 0)", __FUNCTION__); + return SendErrorResponse (0x28); + } + + // Get the thread's register context. + NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); + if (!reg_context_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); + return SendErrorResponse (0x15); + } + + const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); + if (!reg_info) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); + return SendErrorResponse (0x48); + } + + // Return the end of registers response if we've iterated one past the end of the register set. + if (reg_index >= reg_context_sp->GetRegisterCount ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetRegisterCount ()); + return SendErrorResponse (0x47); + } + + + // Build the reginfos response. + StreamGDBRemote response; + + // FIXME Could be suffixed with a thread: parameter. + // That thread then needs to be fed back into the reg context retrieval above. + Error error = reg_context_sp->WriteRegisterFromUnsigned (reg_info, raw_value); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, write of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); + return SendErrorResponse (0x32); + } + + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_H (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Ensure we're llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_H() unimplemented"); + + // Fail if we don't have a current process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); + return SendErrorResponse (0x15); + } + + // Parse out which variant of $H is requested. + packet.SetFilePos (strlen("H")); + if (packet.GetBytesLeft () < 1) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, H command missing {g,c} variant", __FUNCTION__); + return SendIllFormedResponse (packet, "H command missing {g,c} variant"); + } + + const char h_variant = packet.GetChar (); + switch (h_variant) + { + case 'g': + break; + + case 'c': + break; + + default: + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, invalid $H variant %c", __FUNCTION__, h_variant); + return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); + } + + // Parse out the thread number. + // FIXME return a parse success/fail value. All values are valid here. + const lldb::tid_t tid = packet.GetHexMaxU64 (false, std::numeric_limits<lldb::tid_t>::max ()); + + // Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread). + if (tid != LLDB_INVALID_THREAD_ID && tid != 0) + { + NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); + if (!thread_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, tid %" PRIu64 " not found", __FUNCTION__, tid); + return SendErrorResponse (0x15); + } + } + + // Now switch the given thread type. + switch (h_variant) + { + case 'g': + SetCurrentThreadID (tid); + break; + + case 'c': + SetContinueThreadID (tid); + break; + + default: + assert (false && "unsupported $H variant - shouldn't get here"); + return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); + } + + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_interrupt (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + + // Ensure we're llgs. + if (!IsGdbServer()) + { + // Only supported on llgs + return SendUnimplementedResponse (""); + } + + // Fail if we don't have a current process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); + return SendErrorResponse (0x15); + } + + // Build the ResumeActionList - stop everything. + lldb_private::ResumeActionList actions (StateType::eStateStopped, 0); + + Error error = m_debugged_process_sp->Resume (actions); + if (error.Fail ()) + { + if (log) + { + log->Printf ("GDBRemoteCommunicationServer::%s failed for process %" PRIu64 ": %s", + __FUNCTION__, + m_debugged_process_sp->GetID (), + error.AsCString ()); + } + return SendErrorResponse (GDBRemoteServerError::eErrorResume); + } + + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s stopped process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); + + // No response required from stop all. + return PacketResult::Success; +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_m (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Ensure we're llgs. + if (!IsGdbServer()) + { + // Only supported on llgs + return SendUnimplementedResponse (""); + } + + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); + return SendErrorResponse (0x15); + } + + // Parse out the memory address. + packet.SetFilePos (strlen("m")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short m packet"); + + // Read the address. Punting on validation. + // FIXME replace with Hex U64 read with no default value that fails on failed read. + const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); + + // Validate comma. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) + return SendIllFormedResponse(packet, "Comma sep missing in m packet"); + + // Get # bytes to read. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Length missing in m packet"); + + const uint64_t byte_count = packet.GetHexMaxU64(false, 0); + if (byte_count == 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s nothing to read: zero-length packet", __FUNCTION__); + return PacketResult::Success; + } + + // Allocate the response buffer. + std::string buf(byte_count, '\0'); + if (buf.empty()) + return SendErrorResponse (0x78); + + + // Retrieve the process memory. + lldb::addr_t bytes_read = 0; + lldb_private::Error error = m_debugged_process_sp->ReadMemory (read_addr, &buf[0], byte_count, bytes_read); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, error.AsCString ()); + return SendErrorResponse (0x08); + } + + if (bytes_read == 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, bytes_read, byte_count); + return SendErrorResponse (0x08); + } + + StreamGDBRemote response; + for (lldb::addr_t i = 0; i < bytes_read; ++i) + response.PutHex8(buf[i]); + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("QSetDetachOnError:")); + if (packet.GetU32(0)) + m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError); + else + m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError); + return SendOKResponse (); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_M (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Ensure we're llgs. + if (!IsGdbServer()) + { + // Only supported on llgs + return SendUnimplementedResponse (""); + } + + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); + return SendErrorResponse (0x15); + } + + // Parse out the memory address. + packet.SetFilePos (strlen("M")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short M packet"); + + // Read the address. Punting on validation. + // FIXME replace with Hex U64 read with no default value that fails on failed read. + const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0); + + // Validate comma. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) + return SendIllFormedResponse(packet, "Comma sep missing in M packet"); + + // Get # bytes to read. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Length missing in M packet"); + + const uint64_t byte_count = packet.GetHexMaxU64(false, 0); + if (byte_count == 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s nothing to write: zero-length packet", __FUNCTION__); + return PacketResult::Success; + } + + // Validate colon. + if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':')) + return SendIllFormedResponse(packet, "Comma sep missing in M packet after byte length"); + + // Allocate the conversion buffer. + std::vector<uint8_t> buf(byte_count, 0); + if (buf.empty()) + return SendErrorResponse (0x78); + + // Convert the hex memory write contents to bytes. + StreamGDBRemote response; + const uint64_t convert_count = static_cast<uint64_t> (packet.GetHexBytes (&buf[0], byte_count, 0)); + if (convert_count != byte_count) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": asked to write %" PRIu64 " bytes, but only found %" PRIu64 " to convert.", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count, convert_count); + return SendIllFormedResponse (packet, "M content byte length specified did not match hex-encoded content length"); + } + + // Write the process memory. + lldb::addr_t bytes_written = 0; + lldb_private::Error error = m_debugged_process_sp->WriteMemory (write_addr, &buf[0], byte_count, bytes_written); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to write. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, error.AsCString ()); + return SendErrorResponse (0x09); + } + + if (bytes_written == 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": wrote %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, bytes_written, byte_count); + return SendErrorResponse (0x09); + } + + return SendOKResponse (); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse (""); + + // Currently only the NativeProcessProtocol knows if it can handle a qMemoryRegionInfoSupported + // request, but we're not guaranteed to be attached to a process. For now we'll assume the + // client only asks this when a process is being debugged. + + // Ensure we have a process running; otherwise, we can't figure this out + // since we won't have a NativeProcessProtocol. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); + return SendErrorResponse (0x15); + } + + // Test if we can get any region back when asking for the region around NULL. + MemoryRegionInfo region_info; + const Error error = m_debugged_process_sp->GetMemoryRegionInfo (0, region_info); + if (error.Fail ()) + { + // We don't support memory region info collection for this NativeProcessProtocol. + return SendUnimplementedResponse (""); + } + + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse (""); + + // Ensure we have a process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); + return SendErrorResponse (0x15); + } + + // Parse out the memory address. + packet.SetFilePos (strlen("qMemoryRegionInfo:")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet"); + + // Read the address. Punting on validation. + const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); + + StreamGDBRemote response; + + // Get the memory region info for the target address. + MemoryRegionInfo region_info; + const Error error = m_debugged_process_sp->GetMemoryRegionInfo (read_addr, region_info); + if (error.Fail ()) + { + // Return the error message. + + response.PutCString ("error:"); + response.PutCStringAsRawHex8 (error.AsCString ()); + response.PutChar (';'); + } + else + { + // Range start and size. + response.Printf ("start:%" PRIx64 ";size:%" PRIx64 ";", region_info.GetRange ().GetRangeBase (), region_info.GetRange ().GetByteSize ()); + + // Permissions. + if (region_info.GetReadable () || + region_info.GetWritable () || + region_info.GetExecutable ()) + { + // Write permissions info. + response.PutCString ("permissions:"); + + if (region_info.GetReadable ()) + response.PutChar ('r'); + if (region_info.GetWritable ()) + response.PutChar('w'); + if (region_info.GetExecutable()) + response.PutChar ('x'); + + response.PutChar (';'); + } + } + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_Z (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse (""); + + // Ensure we have a process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); + return SendErrorResponse (0x15); + } + + // Parse out software or hardware breakpoint requested. + packet.SetFilePos (strlen("Z")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short Z packet, missing software/hardware specifier"); + + bool want_breakpoint = true; + bool want_hardware = false; + + const char breakpoint_type_char = packet.GetChar (); + switch (breakpoint_type_char) + { + case '0': want_hardware = false; want_breakpoint = true; break; + case '1': want_hardware = true; want_breakpoint = true; break; + case '2': want_breakpoint = false; break; + case '3': want_breakpoint = false; break; + default: + return SendIllFormedResponse(packet, "Z packet had invalid software/hardware specifier"); + + } + + if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') + return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after breakpoint type"); + + // FIXME implement watchpoint support. + if (!want_breakpoint) + return SendUnimplementedResponse ("watchpoint support not yet implemented"); + + // Parse out the breakpoint address. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short Z packet, missing address"); + const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0); + + if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') + return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address"); + + // Parse out the breakpoint kind (i.e. size hint for opcode size). + const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (kind == std::numeric_limits<uint32_t>::max ()) + return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse kind argument"); + + if (want_breakpoint) + { + // Try to set the breakpoint. + const Error error = m_debugged_process_sp->SetBreakpoint (breakpoint_addr, kind, want_hardware); + if (error.Success ()) + return SendOKResponse (); + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to set breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); + return SendErrorResponse (0x09); + } + } + + // FIXME fix up after watchpoints are handled. + return SendUnimplementedResponse (""); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse (""); + + // Ensure we have a process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); + return SendErrorResponse (0x15); + } + + // Parse out software or hardware breakpoint requested. + packet.SetFilePos (strlen("Z")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier"); + + bool want_breakpoint = true; + + const char breakpoint_type_char = packet.GetChar (); + switch (breakpoint_type_char) + { + case '0': want_breakpoint = true; break; + case '1': want_breakpoint = true; break; + case '2': want_breakpoint = false; break; + case '3': want_breakpoint = false; break; + default: + return SendIllFormedResponse(packet, "z packet had invalid software/hardware specifier"); + + } + + if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') + return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after breakpoint type"); + + // FIXME implement watchpoint support. + if (!want_breakpoint) + return SendUnimplementedResponse ("watchpoint support not yet implemented"); + + // Parse out the breakpoint address. + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short z packet, missing address"); + const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0); + + if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') + return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address"); + + // Parse out the breakpoint kind (i.e. size hint for opcode size). + const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ()); + if (kind == std::numeric_limits<uint32_t>::max ()) + return SendIllFormedResponse(packet, "Malformed z packet, failed to parse kind argument"); + + if (want_breakpoint) + { + // Try to set the breakpoint. + const Error error = m_debugged_process_sp->RemoveBreakpoint (breakpoint_addr); + if (error.Success ()) + return SendOKResponse (); + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to remove breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); + return SendErrorResponse (0x09); + } + } + + // FIXME fix up after watchpoints are handled. + return SendUnimplementedResponse (""); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_s (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse (""); + + // Ensure we have a process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); + return SendErrorResponse (0x32); + } + + // We first try to use a continue thread id. If any one or any all set, use the current thread. + // Bail out if we don't have a thread id. + lldb::tid_t tid = GetContinueThreadID (); + if (tid == 0 || tid == LLDB_INVALID_THREAD_ID) + tid = GetCurrentThreadID (); + if (tid == LLDB_INVALID_THREAD_ID) + return SendErrorResponse (0x33); + + // Double check that we have such a thread. + // TODO investigate: on MacOSX we might need to do an UpdateThreads () here. + NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID (tid); + if (!thread_sp || thread_sp->GetID () != tid) + return SendErrorResponse (0x33); + + // Create the step action for the given thread. + lldb_private::ResumeAction action = { tid, eStateStepping, 0 }; + + // Setup the actions list. + lldb_private::ResumeActionList actions; + actions.Append (action); + + // All other threads stop while we're single stepping a thread. + actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); + Error error = m_debugged_process_sp->Resume (actions); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), tid, error.AsCString ()); + return SendErrorResponse(0x49); + } + + // No response here - the stop or exit will come from the resulting action. + return PacketResult::Success; +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_qSupported (StringExtractorGDBRemote &packet) +{ + StreamGDBRemote response; + + // Features common to lldb-platform and llgs. + uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less + response.Printf ("PacketSize=%x", max_packet_size); + + response.PutCString (";QStartNoAckMode+"); + response.PutCString (";QThreadSuffixSupported+"); + response.PutCString (";QListThreadsInStopReply+"); +#if defined(__linux__) + response.PutCString (";qXfer:auxv:read+"); +#endif + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet) +{ + m_thread_suffix_supported = true; + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet) +{ + m_list_threads_in_stop_reply = true; + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet) +{ + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("only supported for lldb-gdbserver"); + + // *BSD impls should be able to do this too. +#if defined(__linux__) + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Parse out the offset. + packet.SetFilePos (strlen("qXfer:auxv:read::")); + if (packet.GetBytesLeft () < 1) + return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); + + const uint64_t auxv_offset = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ()); + if (auxv_offset == std::numeric_limits<uint64_t>::max ()) + return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); + + // Parse out comma. + if (packet.GetBytesLeft () < 1 || packet.GetChar () != ',') + return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing comma after offset"); + + // Parse out the length. + const uint64_t auxv_length = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ()); + if (auxv_length == std::numeric_limits<uint64_t>::max ()) + return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing length"); + + // Grab the auxv data if we need it. + if (!m_active_auxv_buffer_sp) + { + // Make sure we have a valid process. + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__); + return SendErrorResponse (0x10); + } + + // Grab the auxv data. + m_active_auxv_buffer_sp = Host::GetAuxvData (m_debugged_process_sp->GetID ()); + if (!m_active_auxv_buffer_sp || m_active_auxv_buffer_sp->GetByteSize () == 0) + { + // Hmm, no auxv data, call that an error. + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed, no auxv data retrieved", __FUNCTION__); + m_active_auxv_buffer_sp.reset (); + return SendErrorResponse (0x11); + } + } + + // FIXME find out if/how I lock the stream here. + + StreamGDBRemote response; + bool done_with_buffer = false; + + if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize ()) + { + // We have nothing left to send. Mark the buffer as complete. + response.PutChar ('l'); + done_with_buffer = true; + } + else + { + // Figure out how many bytes are available starting at the given offset. + const uint64_t bytes_remaining = m_active_auxv_buffer_sp->GetByteSize () - auxv_offset; + + // Figure out how many bytes we're going to read. + const uint64_t bytes_to_read = (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length; + + // Mark the response type according to whether we're reading the remainder of the auxv data. + if (bytes_to_read >= bytes_remaining) + { + // There will be nothing left to read after this + response.PutChar ('l'); + done_with_buffer = true; + } + else + { + // There will still be bytes to read after this request. + response.PutChar ('m'); + } + + // Now write the data in encoded binary form. + response.PutEscapedBytes (m_active_auxv_buffer_sp->GetBytes () + auxv_offset, bytes_to_read); + } + + if (done_with_buffer) + m_active_auxv_buffer_sp.reset (); + + return SendPacketNoLock(response.GetData(), response.GetSize()); +#else + return SendUnimplementedResponse ("not implemented on this platform"); +#endif +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_QSaveRegisterState (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("only supported for lldb-gdbserver"); + + // Move past packet name. + packet.SetFilePos (strlen ("QSaveRegisterState")); + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); + if (!thread_sp) + { + if (m_thread_suffix_supported) + return SendIllFormedResponse (packet, "No thread specified in QSaveRegisterState packet"); + else + return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); + } + + // Grab the register context for the thread. + NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); + if (!reg_context_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); + return SendErrorResponse (0x15); + } + + // Save registers to a buffer. + DataBufferSP register_data_sp; + Error error = reg_context_sp->ReadAllRegisterValues (register_data_sp); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to save all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); + return SendErrorResponse (0x75); + } + + // Allocate a new save id. + const uint32_t save_id = GetNextSavedRegistersID (); + assert ((m_saved_registers_map.find (save_id) == m_saved_registers_map.end ()) && "GetNextRegisterSaveID() returned an existing register save id"); + + // Save the register data buffer under the save id. + { + Mutex::Locker locker (m_saved_registers_mutex); + m_saved_registers_map[save_id] = register_data_sp; + } + + // Write the response. + StreamGDBRemote response; + response.Printf ("%" PRIu32, save_id); + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("only supported for lldb-gdbserver"); + + // Parse out save id. + packet.SetFilePos (strlen ("QRestoreRegisterState:")); + if (packet.GetBytesLeft () < 1) + return SendIllFormedResponse (packet, "QRestoreRegisterState packet missing register save id"); + + const uint32_t save_id = packet.GetU32 (0); + if (save_id == 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s QRestoreRegisterState packet has malformed save id, expecting decimal uint32_t", __FUNCTION__); + return SendErrorResponse (0x76); + } + + // Get the thread to use. + NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); + if (!thread_sp) + { + if (m_thread_suffix_supported) + return SendIllFormedResponse (packet, "No thread specified in QRestoreRegisterState packet"); + else + return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); + } + + // Grab the register context for the thread. + NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); + if (!reg_context_sp) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); + return SendErrorResponse (0x15); + } + + // Retrieve register state buffer, then remove from the list. + DataBufferSP register_data_sp; + { + Mutex::Locker locker (m_saved_registers_mutex); + + // Find the register set buffer for the given save id. + auto it = m_saved_registers_map.find (save_id); + if (it == m_saved_registers_map.end ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " does not have a register set save buffer for id %" PRIu32, __FUNCTION__, m_debugged_process_sp->GetID (), save_id); + return SendErrorResponse (0x77); + } + register_data_sp = it->second; + + // Remove it from the map. + m_saved_registers_map.erase (it); + } + + Error error = reg_context_sp->WriteAllRegisterValues (register_data_sp); + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to restore all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); + return SendErrorResponse (0x77); + } + + return SendOKResponse(); +} + +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_vAttach (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("only supported for lldb-gdbserver"); + + // Consume the ';' after vAttach. + packet.SetFilePos (strlen ("vAttach")); + if (!packet.GetBytesLeft () || packet.GetChar () != ';') + return SendIllFormedResponse (packet, "vAttach missing expected ';'"); + + // Grab the PID to which we will attach (assume hex encoding). + lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendIllFormedResponse (packet, "vAttach failed to parse the process id"); + + // Attempt to attach. + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s attempting to attach to pid %" PRIu64, __FUNCTION__, pid); + + Error error = AttachToProcess (pid); + + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to attach to pid %" PRIu64 ": %s\n", __FUNCTION__, pid, error.AsCString()); + return SendErrorResponse (0x01); + } + + // Notify we attached by sending a stop packet. + return SendStopReasonForState (m_debugged_process_sp->GetState (), true); + + return PacketResult::Success; +} + +void +GDBRemoteCommunicationServer::FlushInferiorOutput () +{ + // If we're not monitoring an inferior's terminal, ignore this. + if (!m_stdio_communication.IsConnected()) + return; + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s() called", __FUNCTION__); + + // FIXME implement a timeout on the join. + m_stdio_communication.JoinReadThread(); +} + +void +GDBRemoteCommunicationServer::MaybeCloseInferiorTerminalConnection () +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Tell the stdio connection to shut down. + if (m_stdio_communication.IsConnected()) + { + auto connection = m_stdio_communication.GetConnection(); + if (connection) + { + Error error; + connection->Disconnect (&error); + + if (error.Success ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - SUCCESS", __FUNCTION__); + } + else + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - FAIL: %s", __FUNCTION__, error.AsCString ()); + } + } + } +} + + +lldb_private::NativeThreadProtocolSP +GDBRemoteCommunicationServer::GetThreadFromSuffix (StringExtractorGDBRemote &packet) +{ + NativeThreadProtocolSP thread_sp; + + // We have no thread if we don't have a process. + if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) + return thread_sp; + + // If the client hasn't asked for thread suffix support, there will not be a thread suffix. + // Use the current thread in that case. + if (!m_thread_suffix_supported) + { + const lldb::tid_t current_tid = GetCurrentThreadID (); + if (current_tid == LLDB_INVALID_THREAD_ID) + return thread_sp; + else if (current_tid == 0) + { + // Pick a thread. + return m_debugged_process_sp->GetThreadAtIndex (0); + } + else + return m_debugged_process_sp->GetThreadByID (current_tid); + } + + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + + // Parse out the ';'. + if (packet.GetBytesLeft () < 1 || packet.GetChar () != ';') + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected ';' prior to start of thread suffix: packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); + return thread_sp; + } + + if (!packet.GetBytesLeft ()) + return thread_sp; + + // Parse out thread: portion. + if (strncmp (packet.Peek (), "thread:", strlen("thread:")) != 0) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected 'thread:' but not found, packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); + return thread_sp; + } + packet.SetFilePos (packet.GetFilePos () + strlen("thread:")); + const lldb::tid_t tid = packet.GetHexMaxU64(false, 0); + if (tid != 0) + return m_debugged_process_sp->GetThreadByID (tid); + + return thread_sp; +} + +lldb::tid_t +GDBRemoteCommunicationServer::GetCurrentThreadID () const +{ + if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID) + { + // Use whatever the debug process says is the current thread id + // since the protocol either didn't specify or specified we want + // any/all threads marked as the current thread. + if (!m_debugged_process_sp) + return LLDB_INVALID_THREAD_ID; + return m_debugged_process_sp->GetCurrentThreadID (); + } + // Use the specific current thread id set by the gdb remote protocol. + return m_current_tid; +} + +uint32_t +GDBRemoteCommunicationServer::GetNextSavedRegistersID () +{ + Mutex::Locker locker (m_saved_registers_mutex); + return m_next_saved_registers_id++; +} + +void +GDBRemoteCommunicationServer::ClearProcessSpecificData () +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|GDBR_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s()", __FUNCTION__); + + // Clear any auxv cached data. + // *BSD impls should be able to do this too. +#if defined(__linux__) + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s clearing auxv buffer (previously %s)", + __FUNCTION__, + m_active_auxv_buffer_sp ? "was set" : "was not set"); + m_active_auxv_buffer_sp.reset (); +#endif +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 913c6b6..13c037c 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -14,16 +14,23 @@ // C++ Includes #include <vector> #include <set> +#include <unordered_map> // Other libraries and framework includes // Project includes +#include "lldb/lldb-private-forward.h" +#include "lldb/Core/Communication.h" #include "lldb/Host/Mutex.h" #include "lldb/Target/Process.h" #include "GDBRemoteCommunication.h" +#include "../../../Host/common/NativeProcessProtocol.h" + class ProcessGDBRemote; class StringExtractorGDBRemote; -class GDBRemoteCommunicationServer : public GDBRemoteCommunication +class GDBRemoteCommunicationServer : + public GDBRemoteCommunication, + public lldb_private::NativeProcessProtocol::NativeDelegate { public: typedef std::map<uint16_t, lldb::pid_t> PortMap; @@ -38,12 +45,13 @@ public: GDBRemoteCommunicationServer(bool is_platform); GDBRemoteCommunicationServer(bool is_platform, - const lldb::PlatformSP& platform_sp); + const lldb::PlatformSP& platform_sp, + lldb::DebuggerSP& debugger_sp); virtual ~GDBRemoteCommunicationServer(); - bool + PacketResult GetPacketAndSendResponse (uint32_t timeout_usec, lldb_private::Error &error, bool &interrupt, @@ -188,6 +196,31 @@ public: lldb_private::Error LaunchProcess (); + //------------------------------------------------------------------ + /// Attach to a process. + /// + /// This method supports attaching llgs to a process accessible via the + /// configured Platform. + /// + /// @return + /// An Error object indicating the success or failure of the + /// attach operation. + //------------------------------------------------------------------ + lldb_private::Error + AttachToProcess (lldb::pid_t pid); + + //------------------------------------------------------------------ + // NativeProcessProtocol::NativeDelegate overrides + //------------------------------------------------------------------ + void + InitializeDelegate (lldb_private::NativeProcessProtocol *process) override; + + void + ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state) override; + + void + DidExec (lldb_private::NativeProcessProtocol *process) override; + protected: lldb::PlatformSP m_platform_sp; lldb::thread_t m_async_thread; @@ -199,7 +232,20 @@ protected: uint32_t m_proc_infos_index; PortMap m_port_map; uint16_t m_port_offset; - + lldb::tid_t m_current_tid; + lldb::tid_t m_continue_tid; + lldb_private::Mutex m_debugged_process_mutex; + lldb_private::NativeProcessProtocolSP m_debugged_process_sp; + lldb::DebuggerSP m_debugger_sp; + Communication m_stdio_communication; + bool m_exit_now; // use in asynchronous handling to indicate process should exit. + lldb::StateType m_inferior_prev_state; + bool m_thread_suffix_supported; + bool m_list_threads_in_stop_reply; + lldb::DataBufferSP m_active_auxv_buffer_sp; + lldb_private::Mutex m_saved_registers_mutex; + std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map; + uint32_t m_next_saved_registers_id; PacketResult SendUnimplementedResponse (const char *packet); @@ -208,9 +254,24 @@ protected: SendErrorResponse (uint8_t error); PacketResult + SendIllFormedResponse (const StringExtractorGDBRemote &packet, const char *error_message); + + PacketResult SendOKResponse (); PacketResult + SendONotification (const char *buffer, uint32_t len); + + PacketResult + SendWResponse (lldb_private::NativeProcessProtocol *process); + + PacketResult + SendStopReplyPacketForThread (lldb::tid_t tid); + + PacketResult + SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit); + + PacketResult Handle_A (StringExtractorGDBRemote &packet); PacketResult @@ -233,7 +294,10 @@ protected: PacketResult Handle_qPlatform_chmod (StringExtractorGDBRemote &packet); - + + PacketResult + Handle_qProcessInfo (StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); @@ -265,6 +329,9 @@ protected: Handle_QSetDisableASLR (StringExtractorGDBRemote &packet); PacketResult + Handle_QSetDetachOnError (StringExtractorGDBRemote &packet); + + PacketResult Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); PacketResult @@ -281,7 +348,22 @@ protected: PacketResult Handle_QSetSTDERR (StringExtractorGDBRemote &packet); - + + PacketResult + Handle_C (StringExtractorGDBRemote &packet); + + PacketResult + Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment = false); + + PacketResult + Handle_vCont (StringExtractorGDBRemote &packet); + + PacketResult + Handle_vCont_actions (StringExtractorGDBRemote &packet); + + PacketResult + Handle_stop_reason (StringExtractorGDBRemote &packet); + PacketResult Handle_vFile_Open (StringExtractorGDBRemote &packet); @@ -318,6 +400,87 @@ protected: PacketResult Handle_qPlatform_shell (StringExtractorGDBRemote &packet); + PacketResult + Handle_qRegisterInfo (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qfThreadInfo (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qsThreadInfo (StringExtractorGDBRemote &packet); + + PacketResult + Handle_p (StringExtractorGDBRemote &packet); + + PacketResult + Handle_P (StringExtractorGDBRemote &packet); + + PacketResult + Handle_H (StringExtractorGDBRemote &packet); + + PacketResult + Handle_interrupt (StringExtractorGDBRemote &packet); + + PacketResult + Handle_m (StringExtractorGDBRemote &packet); + + PacketResult + Handle_M (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet); + + PacketResult + Handle_Z (StringExtractorGDBRemote &packet); + + PacketResult + Handle_z (StringExtractorGDBRemote &packet); + + PacketResult + Handle_s (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qSupported (StringExtractorGDBRemote &packet); + + PacketResult + Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet); + + PacketResult + Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet); + + PacketResult + Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet); + + PacketResult + Handle_QSaveRegisterState (StringExtractorGDBRemote &packet); + + PacketResult + Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet); + + PacketResult + Handle_vAttach (StringExtractorGDBRemote &packet); + + void + SetCurrentThreadID (lldb::tid_t tid); + + lldb::tid_t + GetCurrentThreadID () const; + + void + SetContinueThreadID (lldb::tid_t tid); + + lldb::tid_t + GetContinueThreadID () const { return m_continue_tid; } + + lldb_private::Error + SetSTDIOFileDescriptor (int fd); + + static void + STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len); + private: bool DebugserverProcessReaped (lldb::pid_t pid); @@ -342,6 +505,41 @@ private: bool KillSpawnedProcess (lldb::pid_t pid); + bool + IsGdbServer () + { + return !m_is_platform; + } + + /// Launch a process from lldb-gdbserver + lldb_private::Error + LaunchDebugServerProcess (); + + /// Launch a process from lldb-platform + lldb_private::Error + LaunchPlatformProcess (); + + void + HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process); + + void + HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process); + + void + FlushInferiorOutput (); + + lldb_private::NativeThreadProtocolSP + GetThreadFromSuffix (StringExtractorGDBRemote &packet); + + uint32_t + GetNextSavedRegistersID (); + + void + MaybeCloseInferiorTerminalConnection (); + + void + ClearProcessSpecificData (); + //------------------------------------------------------------------ // For GDBRemoteCommunicationServer only //------------------------------------------------------------------ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 73b9b3e..6d7eca1 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -21,6 +21,7 @@ #include "lldb/Interpreter/PythonDataObjects.h" #endif #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" #include "lldb/Utility/Utils.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -199,7 +200,7 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE const uint32_t prim_reg = reg_info->value_regs[idx]; if (prim_reg == LLDB_INVALID_REGNUM) break; - // We have a valid primordial regsiter as our constituent. + // We have a valid primordial register as our constituent. // Grab the corresponding register info. const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); if (prim_reg_info == NULL) @@ -232,11 +233,20 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE if (&data != &m_reg_data) { +#if defined (LLDB_CONFIGURATION_DEBUG) + assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size); +#endif + // If our register context and our register info disagree, which should never happen, don't + // read past the end of the buffer. + if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) + return false; + // If we aren't extracting into our own buffer (which // only happens when this function is called from // ReadRegisterValue(uint32_t, Scalar&)) then // we transfer bytes from our buffer into the data // buffer that was passed in + data.SetByteOrder (m_reg_data.GetByteOrder()); data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size); } @@ -322,6 +332,16 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo * // if (gdb_comm.IsRunning()) // return false; + +#if defined (LLDB_CONFIGURATION_DEBUG) + assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size); +#endif + + // If our register context and our register info disagree, which should never happen, don't + // overwrite past the end of the buffer. + if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) + return false; + // Grab a pointer to where we are going to put this register uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); @@ -389,7 +409,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo * const uint32_t reg = reg_info->value_regs[idx]; if (reg == LLDB_INVALID_REGNUM) break; - // We have a valid primordial regsiter as our constituent. + // We have a valid primordial register as our constituent. // Grab the corresponding register info. const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg); if (value_reg_info == NULL) @@ -502,6 +522,8 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) StringExtractorGDBRemote response; + const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers.")) { @@ -519,29 +541,62 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) + if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsErrorResponse()) - return false; - - std::string &response_str = response.GetStringRef(); - if (isxdigit(response_str[0])) + int packet_len = 0; + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID()); + else + packet_len = ::snprintf (packet, sizeof(packet), "g"); + assert (packet_len < ((int)sizeof(packet) - 1)); + + if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { - response_str.insert(0, 1, 'G'); - if (thread_suffix_supported) + if (response.IsErrorResponse()) + return false; + + std::string &response_str = response.GetStringRef(); + if (isxdigit(response_str[0])) { - char thread_id_cstr[64]; - ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - response_str.append (thread_id_cstr); + response_str.insert(0, 1, 'G'); + if (thread_suffix_supported) + { + char thread_id_cstr[64]; + ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + response_str.append (thread_id_cstr); + } + data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size())); + return true; } - data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size())); - return true; } } + else + { + // For the use_g_packet == false case, we're going to read each register + // individually and store them as binary data in a buffer instead of as ascii + // characters. + const RegisterInfo *reg_info; + + // data_sp will take ownership of this DataBufferHeap pointer soon. + DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0)); + + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) + { + if (reg_info->value_regs) // skip registers that are slices of real registers + continue; + ReadRegisterBytes (reg_info, m_reg_data); + // ReadRegisterBytes saves the contents of the register in to the m_reg_data buffer + } + memcpy (reg_ctx->GetBytes(), m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize()); + + data_sp = reg_ctx; + return true; + } } } else { + Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); if (log) { @@ -575,6 +630,8 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + StringExtractorGDBRemote response; Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers.")) @@ -588,63 +645,126 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data // as well. const char *G_packet = (const char *)data_sp->GetBytes(); size_t G_packet_len = data_sp->GetByteSize(); - if (gdb_comm.SendPacketAndWaitForResponse (G_packet, - G_packet_len, - response, - false) == GDBRemoteCommunication::PacketResult::Success) + if (use_g_packet + && gdb_comm.SendPacketAndWaitForResponse (G_packet, + G_packet_len, + response, + false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsOKResponse()) - return true; - else if (response.IsErrorResponse()) + // The data_sp contains the entire G response packet including the + // G, and if the thread suffix is supported, it has the thread suffix + // as well. + const char *G_packet = (const char *)data_sp->GetBytes(); + size_t G_packet_len = data_sp->GetByteSize(); + if (gdb_comm.SendPacketAndWaitForResponse (G_packet, + G_packet_len, + response, + false) == GDBRemoteCommunication::PacketResult::Success) { - uint32_t num_restored = 0; - // We need to manually go through all of the registers and - // restore them manually - - response.GetStringRef().assign (G_packet, G_packet_len); - response.SetFilePos(1); // Skip the leading 'G' - DataBufferHeap buffer (m_reg_data.GetByteSize(), 0); - DataExtractor restore_data (buffer.GetBytes(), - buffer.GetByteSize(), - m_reg_data.GetByteOrder(), - m_reg_data.GetAddressByteSize()); - - const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(), - restore_data.GetByteSize(), - '\xcc'); - - if (bytes_extracted < restore_data.GetByteSize()) - restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder()); - - //ReadRegisterBytes (const RegisterInfo *reg_info, RegisterValue &value, DataExtractor &data) - const RegisterInfo *reg_info; - // We have to march the offset of each register along in the - // buffer to make sure we get the right offset. - uint32_t reg_byte_offset = 0; - for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, reg_byte_offset += reg_info->byte_size) + if (response.IsOKResponse()) + return true; + else if (response.IsErrorResponse()) { - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - // Skip composite registers. - if (reg_info->value_regs) - continue; + uint32_t num_restored = 0; + // We need to manually go through all of the registers and + // restore them manually + + response.GetStringRef().assign (G_packet, G_packet_len); + response.SetFilePos(1); // Skip the leading 'G' + + // G_packet_len is hex-ascii characters plus prefix 'G' plus suffix thread specifier. + // This means buffer will be a little more than 2x larger than necessary but we resize + // it down once we've extracted all hex ascii chars from the packet. + DataBufferHeap buffer (G_packet_len, 0); + DataExtractor restore_data (buffer.GetBytes(), + buffer.GetByteSize(), + m_reg_data.GetByteOrder(), + m_reg_data.GetAddressByteSize()); + + const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(), + restore_data.GetByteSize(), + '\xcc'); + + if (bytes_extracted < restore_data.GetByteSize()) + restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder()); + + const RegisterInfo *reg_info; + + // The g packet contents may either include the slice registers (registers defined in + // terms of other registers, e.g. eax is a subset of rax) or not. The slice registers + // should NOT be in the g packet, but some implementations may incorrectly include them. + // + // If the slice registers are included in the packet, we must step over the slice registers + // when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect. + // If the slice registers are not included, then using the byte_offset values into the + // data buffer is the best way to find individual register values. + + uint64_t size_including_slice_registers = 0; + uint64_t size_not_including_slice_registers = 0; + uint64_t size_by_highest_offset = 0; + + for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx) + { + size_including_slice_registers += reg_info->byte_size; + if (reg_info->value_regs == NULL) + size_not_including_slice_registers += reg_info->byte_size; + if (reg_info->byte_offset >= size_by_highest_offset) + size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size; + } - // Only write down the registers that need to be written - // if we are going to be doing registers individually. - bool write_reg = true; - const uint32_t reg_byte_size = reg_info->byte_size; + bool use_byte_offset_into_buffer; + if (size_by_highest_offset == restore_data.GetByteSize()) + { + // The size of the packet agrees with the highest offset: + size in the register file + use_byte_offset_into_buffer = true; + } + else if (size_not_including_slice_registers == restore_data.GetByteSize()) + { + // The size of the packet is the same as concatenating all of the registers sequentially, + // skipping the slice registers + use_byte_offset_into_buffer = true; + } + else if (size_including_slice_registers == restore_data.GetByteSize()) + { + // The slice registers are present in the packet (when they shouldn't be). + // Don't try to use the RegisterInfo byte_offset into the restore_data, it will + // point to the wrong place. + use_byte_offset_into_buffer = false; + } + else { + // None of our expected sizes match the actual g packet data we're looking at. + // The most conservative approach here is to use the running total byte offset. + use_byte_offset_into_buffer = false; + } - const char *restore_src = (const char *)restore_data.PeekData(reg_byte_offset, reg_byte_size); - if (restore_src) + // In case our register definitions don't include the correct offsets, + // keep track of the size of each reg & compute offset based on that. + uint32_t running_byte_offset = 0; + for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, running_byte_offset += reg_info->byte_size) { - if (GetRegisterIsValid(reg)) + // Skip composite aka slice registers (e.g. eax is a slice of rax). + if (reg_info->value_regs) + continue; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + uint32_t register_offset; + if (use_byte_offset_into_buffer) { - const char *current_src = (const char *)m_reg_data.PeekData(reg_byte_offset, reg_byte_size); - if (current_src) - write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0; + register_offset = reg_info->byte_offset; + } + else + { + register_offset = running_byte_offset; } - if (write_reg) + // Only write down the registers that need to be written + // if we are going to be doing registers individually. + bool write_reg = true; + const uint32_t reg_byte_size = reg_info->byte_size; + + const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size); + if (restore_src) { StreamString packet; packet.Printf ("P%x=", reg); @@ -662,14 +782,88 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data response, false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsOKResponse()) - ++num_restored; + const char *current_src = (const char *)m_reg_data.PeekData(register_offset, reg_byte_size); + if (current_src) + write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0; + } + + if (write_reg) + { + StreamString packet; + packet.Printf ("P%x=", reg); + packet.PutBytesAsRawHex8 (restore_src, + reg_byte_size, + lldb::endian::InlHostByteOrder(), + lldb::endian::InlHostByteOrder()); + + if (thread_suffix_supported) + packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + + SetRegisterIsValid(reg, false); + if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), + packet.GetString().size(), + response, + false) == GDBRemoteCommunication::PacketResult::Success) + { + if (response.IsOKResponse()) + ++num_restored; + } } } } + return num_restored > 0; + } + } + } + else + { + // For the use_g_packet == false case, we're going to write each register + // individually. The data buffer is binary data in this case, instead of + // ascii characters. + + bool arm64_debugserver = false; + if (m_thread.GetProcess().get()) + { + const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); + if (arch.IsValid() + && arch.GetMachine() == llvm::Triple::aarch64 + && arch.GetTriple().getVendor() == llvm::Triple::Apple + && arch.GetTriple().getOS() == llvm::Triple::IOS) + { + arm64_debugserver = true; + } + } + uint32_t num_restored = 0; + const RegisterInfo *reg_info; + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) + { + if (reg_info->value_regs) // skip registers that are slices of real registers + continue; + // Skip the fpsr and fpcr floating point status/control register writing to + // work around a bug in an older version of debugserver that would lead to + // register context corruption when writing fpsr/fpcr. + if (arm64_debugserver && + (strcmp (reg_info->name, "fpsr") == 0 || strcmp (reg_info->name, "fpcr") == 0)) + { + continue; + } + StreamString packet; + packet.Printf ("P%x=", reg_info->kinds[eRegisterKindLLDB]); + packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder()); + if (thread_suffix_supported) + packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + + SetRegisterIsValid(reg_info, false); + if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), + packet.GetString().size(), + response, + false) == GDBRemoteCommunication::PacketResult::Success) + { + if (response.IsOKResponse()) + ++num_restored; } - return num_restored > 0; } + return num_restored > 0; } } } @@ -693,7 +887,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data uint32_t -GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 38f29bb..b773814 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -98,7 +98,7 @@ public: WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint); virtual uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num); protected: friend class ThreadGDBRemote; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 326efd4..46d0540 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -56,11 +56,14 @@ #include "lldb/Target/Target.h" #include "lldb/Target/TargetList.h" #include "lldb/Target/ThreadPlanCallFunction.h" +#include "lldb/Target/SystemRuntime.h" #include "lldb/Utility/PseudoTerminal.h" // Project includes #include "lldb/Host/Host.h" +#include "Plugins/Process/Utility/FreeBSDSignals.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" +#include "Plugins/Process/Utility/LinuxSignals.h" #include "Plugins/Process/Utility/StopInfoMachException.h" #include "Utility/StringExtractorGDBRemote.h" #include "GDBRemoteRegisterContext.h" @@ -165,8 +168,6 @@ namespace { } // anonymous namespace end -static bool rand_initialized = false; - // TODO Randomly assigning a port is unsafe. We should get an unused // ephemeral port from the kernel and make sure we reserve it before passing // it to debugserver. @@ -179,19 +180,22 @@ static bool rand_initialized = false; #define HIGH_PORT (49151u) #endif +#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) +static bool rand_initialized = false; + static inline uint16_t get_random_port () { if (!rand_initialized) { time_t seed = time(NULL); - + rand_initialized = true; srand(seed); } return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT; } - +#endif lldb_private::ConstString ProcessGDBRemote::GetPluginNameStatic() @@ -242,6 +246,7 @@ ProcessGDBRemote::CanDebug (Target &target, bool plugin_specified_by_name) case ObjectFile::eTypeObjectFile: case ObjectFile::eTypeSharedLibrary: case ObjectFile::eTypeStubLibrary: + case ObjectFile::eTypeJIT: return false; case ObjectFile::eTypeExecutable: case ObjectFile::eTypeDynamicLinker: @@ -274,7 +279,8 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) : m_continue_C_tids (), m_continue_s_tids (), m_continue_S_tids (), - m_max_memory_size (512), + m_max_memory_size (0), + m_remote_stub_max_memory_size (0), m_addr_to_mmap_size (), m_thread_create_bp_sp (), m_waiting_for_attach (false), @@ -623,6 +629,7 @@ ProcessGDBRemote::WillAttachToProcessWithName (const char *process_name, bool wa Error ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) { + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); Error error (WillLaunchOrAttach ()); if (error.Fail()) @@ -673,7 +680,11 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but no stop reply packet was received", pid, remote_url); } - if (error.Success() + if (log) + log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalizing target architecture initial triple: %s (GetTarget().GetArchitecture().IsValid() %s, m_gdb_comm.GetHostArchitecture().IsValid(): %s)", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str (), GetTarget ().GetArchitecture ().IsValid () ? "true" : "false", m_gdb_comm.GetHostArchitecture ().IsValid () ? "true" : "false"); + + + if (error.Success() && !GetTarget().GetArchitecture().IsValid() && m_gdb_comm.GetHostArchitecture().IsValid()) { @@ -684,6 +695,42 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture()); } + if (log) + log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalized target architecture triple: %s", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str ()); + + // Set the Unix signals properly for the target. + // FIXME Add a gdb-remote packet to discover dynamically. + if (error.Success ()) + { + const ArchSpec arch_spec = GetTarget ().GetArchitecture (); + if (arch_spec.IsValid ()) + { + if (log) + log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": determining unix signals type based on architecture %s, triple %s", __FUNCTION__, GetID (), arch_spec.GetArchitectureName () ? arch_spec.GetArchitectureName () : "<null>", arch_spec.GetTriple ().getTriple ().c_str ()); + + switch (arch_spec.GetTriple ().getOS ()) + { + case llvm::Triple::Linux: + SetUnixSignals (UnixSignalsSP (new process_linux::LinuxSignals ())); + if (log) + log->Printf ("ProcessGDBRemote::%s using Linux unix signals type for pid %" PRIu64, __FUNCTION__, GetID ()); + break; + case llvm::Triple::OpenBSD: + case llvm::Triple::FreeBSD: + case llvm::Triple::NetBSD: + SetUnixSignals (UnixSignalsSP (new FreeBSDSignals ())); + if (log) + log->Printf ("ProcessGDBRemote::%s using *BSD unix signals type for pid %" PRIu64, __FUNCTION__, GetID ()); + break; + default: + SetUnixSignals (UnixSignalsSP (new UnixSignals ())); + if (log) + log->Printf ("ProcessGDBRemote::%s using generic unix signals type for pid %" PRIu64, __FUNCTION__, GetID ()); + break; + } + } + } + return error; } @@ -709,23 +756,23 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) const char *stderr_path = NULL; const char *working_dir = launch_info.GetWorkingDirectory(); - const ProcessLaunchInfo::FileAction *file_action; + const FileAction *file_action; file_action = launch_info.GetFileActionForFD (STDIN_FILENO); if (file_action) { - if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen) + if (file_action->GetAction() == FileAction::eFileActionOpen) stdin_path = file_action->GetPath(); } file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); if (file_action) { - if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen) + if (file_action->GetAction() == FileAction::eFileActionOpen) stdout_path = file_action->GetPath(); } file_action = launch_info.GetFileActionForFD (STDERR_FILENO); if (file_action) { - if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen) + if (file_action->GetAction() == FileAction::eFileActionOpen) stderr_path = file_action->GetPath(); } @@ -794,9 +841,14 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) m_gdb_comm.SetSTDERR (stderr_path); m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR); + m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError); m_gdb_comm.SendLaunchArchPacket (m_target.GetArchitecture().GetArchitectureName()); + const char * launch_event_data = launch_info.GetLaunchEventData(); + if (launch_event_data != NULL && *launch_event_data != '\0') + m_gdb_comm.SendLaunchEventDataPacket (launch_event_data); + if (working_dir && working_dir[0]) { m_gdb_comm.SetWorkingDir (working_dir); @@ -957,7 +1009,7 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url) } void -ProcessGDBRemote::DidLaunchOrAttach () +ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) @@ -968,16 +1020,17 @@ ProcessGDBRemote::DidLaunchOrAttach () // See if the GDB server supports the qHostInfo information - ArchSpec gdb_remote_arch = m_gdb_comm.GetHostArchitecture(); // See if the GDB server supports the qProcessInfo packet, if so // prefer that over the Host information as it will be more specific // to our process. if (m_gdb_comm.GetProcessArchitecture().IsValid()) - gdb_remote_arch = m_gdb_comm.GetProcessArchitecture(); + process_arch = m_gdb_comm.GetProcessArchitecture(); + else + process_arch = m_gdb_comm.GetHostArchitecture(); - if (gdb_remote_arch.IsValid()) + if (process_arch.IsValid()) { ArchSpec &target_arch = GetTarget().GetArchitecture(); @@ -990,15 +1043,15 @@ ProcessGDBRemote::DidLaunchOrAttach () // it has, so we really need to take the remote host architecture as our // defacto architecture in this case. - if (gdb_remote_arch.GetMachine() == llvm::Triple::arm && - gdb_remote_arch.GetTriple().getVendor() == llvm::Triple::Apple) + if (process_arch.GetMachine() == llvm::Triple::arm && + process_arch.GetTriple().getVendor() == llvm::Triple::Apple) { - target_arch = gdb_remote_arch; + GetTarget().SetArchitecture (process_arch); } else { // Fill in what is missing in the triple - const llvm::Triple &remote_triple = gdb_remote_arch.GetTriple(); + const llvm::Triple &remote_triple = process_arch.GetTriple(); llvm::Triple &target_triple = target_arch.GetTriple(); if (target_triple.getVendorName().size() == 0) { @@ -1018,7 +1071,7 @@ ProcessGDBRemote::DidLaunchOrAttach () { // The target doesn't have a valid architecture yet, set it from // the architecture we got from the remote GDB server - target_arch = gdb_remote_arch; + GetTarget().SetArchitecture (process_arch); } } } @@ -1027,7 +1080,8 @@ ProcessGDBRemote::DidLaunchOrAttach () void ProcessGDBRemote::DidLaunch () { - DidLaunchOrAttach (); + ArchSpec process_arch; + DidLaunchOrAttach (process_arch); } Error @@ -1062,6 +1116,8 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process if (error.Success()) { + m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); + char packet[64]; const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid); SetID (attach_pid); @@ -1099,6 +1155,8 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const Pro { StreamString packet; + m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); + if (attach_info.GetWaitForLaunch()) { if (!m_gdb_comm.GetVAttachOrWaitSupported()) @@ -1134,9 +1192,11 @@ ProcessGDBRemote::SetExitStatus (int exit_status, const char *cstr) } void -ProcessGDBRemote::DidAttach () +ProcessGDBRemote::DidAttach (ArchSpec &process_arch) { - DidLaunchOrAttach (); + // If you can figure out what the architecture is, fill it in here. + process_arch.Clear(); + DidLaunchOrAttach (process_arch); } @@ -1451,8 +1511,7 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) log->Printf( "ProcessGDBRemote::%s Making new thread: %p for thread ID: 0x%" PRIx64 ".\n", - __FUNCTION__, - thread_sp.get(), + __FUNCTION__, static_cast<void*>(thread_sp.get()), thread_sp->GetID()); } else @@ -1460,8 +1519,7 @@ ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) log->Printf( "ProcessGDBRemote::%s Found old thread: %p for thread ID: 0x%" PRIx64 ".\n", - __FUNCTION__, - thread_sp.get(), + __FUNCTION__, static_cast<void*>(thread_sp.get()), thread_sp->GetID()); } new_thread_list.AddThread(thread_sp); @@ -1556,9 +1614,9 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) log->Printf ("ProcessGDBRemote::%s Adding new thread: %p for thread ID: 0x%" PRIx64 ".\n", __FUNCTION__, - thread_sp.get(), + static_cast<void*>(thread_sp.get()), thread_sp->GetID()); - + m_thread_list_real.AddThread(thread_sp); } gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get()); @@ -1581,7 +1639,6 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) if (tid != LLDB_INVALID_THREAD_ID) m_thread_ids.push_back (tid); value.erase(0, comma_pos + 1); - } tid = Args::StringToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); if (tid != LLDB_INVALID_THREAD_ID) @@ -1708,7 +1765,6 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) thread_sp->SetStopInfo (invalid_stop_info_sp); } } - } else if (reason.compare("trap") == 0) { @@ -1733,7 +1789,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) handled = true; } } - + if (!handled && signo && did_exec == false) { if (signo == SIGTRAP) @@ -1743,7 +1799,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) handled = true; addr_t pc = thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset; lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - + if (bp_site_sp) { // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, @@ -1775,7 +1831,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) if (!handled) thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo)); } - + if (!description.empty()) { lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ()); @@ -1795,6 +1851,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) break; case 'W': + case 'X': // process exited return eStateExited; @@ -1863,10 +1920,6 @@ ProcessGDBRemote::DoDetach(bool keep_stopped) if (log) log->Printf ("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped); - DisableAllBreakpointSites (); - - m_thread_list.DiscardThreadPlans(); - error = m_gdb_comm.Detach (keep_stopped); if (log) { @@ -1928,7 +1981,7 @@ ProcessGDBRemote::DoDestroy () if (m_destroy_tried_resuming) { if (log) - log->PutCString ("ProcessGDBRemote::DoDestroy()Tried resuming to destroy once already, not doing it again."); + log->PutCString ("ProcessGDBRemote::DoDestroy() - Tried resuming to destroy once already, not doing it again."); } else { @@ -2065,7 +2118,7 @@ ProcessGDBRemote::DoDestroy () else { if (log) - log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet"); + log->Printf ("ProcessGDBRemote::DoDestroy - killed or interrupted while attaching"); exit_string.assign ("killed or interrupted while attaching."); } } @@ -2125,6 +2178,7 @@ ProcessGDBRemote::GetImageInfoAddress() size_t ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error) { + GetMaxMemorySize (); if (size > m_max_memory_size) { // Keep memory read sizes down to a sane limit. This function will be @@ -2134,7 +2188,16 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro } char packet[64]; - const int packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size); + int packet_len; + bool binary_memory_read = m_gdb_comm.GetxPacketSupported(); + if (binary_memory_read) + { + packet_len = ::snprintf (packet, sizeof(packet), "x0x%" PRIx64 ",0x%" PRIx64, (uint64_t)addr, (uint64_t)size); + } + else + { + packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size); + } assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true) == GDBRemoteCommunication::PacketResult::Success) @@ -2142,7 +2205,25 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro if (response.IsNormalResponse()) { error.Clear(); - return response.GetHexBytes(buf, size, '\xdd'); + if (binary_memory_read) + { + // The lower level GDBRemoteCommunication packet receive layer has already de-quoted any + // 0x7d character escaping that was present in the packet + + size_t data_received_size = response.GetBytesLeft(); + if (data_received_size > size) + { + // Don't write past the end of BUF if the remote debug server gave us too + // much data for some reason. + data_received_size = size; + } + memcpy (buf, response.GetStringRef().data(), data_received_size); + return data_received_size; + } + else + { + return response.GetHexBytes(buf, size, '\xdd'); + } } else if (response.IsErrorResponse()) error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr); @@ -2161,6 +2242,7 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro size_t ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error) { + GetMaxMemorySize (); if (size > m_max_memory_size) { // Keep memory read sizes down to a sane limit. This function will be @@ -2197,6 +2279,7 @@ ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Erro lldb::addr_t ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error) { + lldb_private::Log *log (lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_EXPRESSIONS)); addr_t allocated_addr = LLDB_INVALID_ADDRESS; LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory(); @@ -2222,7 +2305,11 @@ ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &er eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) m_addr_to_mmap_size[allocated_addr] = size; else + { allocated_addr = LLDB_INVALID_ADDRESS; + if (log) + log->Printf ("ProcessGDBRemote::%s no direct stub support for memory allocation, and InferiorCallMmap also failed - is stub missing register context save/restore capability?", __FUNCTION__); + } break; } @@ -2394,7 +2481,7 @@ ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site) return error; } - // We will reach here when the stub gives an unsported response to a hardware breakpoint + // We will reach here when the stub gives an unsupported response to a hardware breakpoint if (log) log->Printf("Hardware breakpoints are unsupported"); @@ -2441,8 +2528,16 @@ ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site) break; case BreakpointSite::eExternal: - if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, addr, bp_op_size)) + { + GDBStoppointType stoppoint_type; + if (bp_site->IsHardware()) + stoppoint_type = eBreakpointHardware; + else + stoppoint_type = eBreakpointSoftware; + + if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr, bp_op_size)) error.SetErrorToGenericError(); + } break; } if (error.Success()) @@ -2603,9 +2698,9 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); debugserver_launch_info.SetUserID(process_info.GetUserID()); -#if defined (__APPLE__) && defined (__arm__) +#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) // On iOS, still do a local connection using a random port - const char *hostname = "localhost"; + const char *hostname = "127.0.0.1"; uint16_t port = get_random_port (); #else // Set hostname being NULL to do the reverse connect where debugserver @@ -2919,13 +3014,33 @@ ProcessGDBRemote::AsyncThread (void *arg) break; case eStateExited: + { process->SetLastStopPacket (response); process->ClearThreadIDList(); response.SetFilePos(1); - process->SetExitStatus(response.GetHexU8(), NULL); + + int exit_status = response.GetHexU8(); + const char *desc_cstr = NULL; + StringExtractor extractor; + std::string desc_string; + if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') + { + std::string desc_token; + while (response.GetNameColonValue (desc_token, desc_string)) + { + if (desc_token == "description") + { + extractor.GetStringRef().swap(desc_string); + extractor.SetFilePos(0); + extractor.GetHexByteString (desc_string); + desc_cstr = desc_string.c_str(); + } + } + } + process->SetExitStatus(exit_status, desc_cstr); done = true; break; - + } case eStateInvalid: process->SetExitStatus(-1, "lost connection"); break; @@ -3061,6 +3176,146 @@ ProcessGDBRemote::GetDynamicLoader () return m_dyld_ap.get(); } +Error +ProcessGDBRemote::SendEventData(const char *data) +{ + int return_value; + bool was_supported; + + Error error; + + return_value = m_gdb_comm.SendLaunchEventDataPacket (data, &was_supported); + if (return_value != 0) + { + if (!was_supported) + error.SetErrorString("Sending events is not supported for this process."); + else + error.SetErrorStringWithFormat("Error sending event data: %d.", return_value); + } + return error; +} + +const DataBufferSP +ProcessGDBRemote::GetAuxvData() +{ + DataBufferSP buf; + if (m_gdb_comm.GetQXferAuxvReadSupported()) + { + std::string response_string; + if (m_gdb_comm.SendPacketsAndConcatenateResponses("qXfer:auxv:read::", response_string) == GDBRemoteCommunication::PacketResult::Success) + buf.reset(new DataBufferHeap(response_string.c_str(), response_string.length())); + } + return buf; +} + +StructuredData::ObjectSP +ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid) +{ + StructuredData::ObjectSP object_sp; + + if (m_gdb_comm.GetThreadExtendedInfoSupported()) + { + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + SystemRuntime *runtime = GetSystemRuntime(); + if (runtime) + { + runtime->AddThreadExtendedInfoPacketHints (args_dict); + } + args_dict->GetAsDictionary()->AddIntegerItem ("thread", tid); + + StreamString packet; + packet << "jThreadExtendedInfo:"; + args_dict->Dump (packet); + + // FIXME the final character of a JSON dictionary, '}', is the escape + // character in gdb-remote binary mode. lldb currently doesn't escape + // these characters in its packet output -- so we add the quoted version + // of the } character here manually in case we talk to a debugserver which + // un-escapes the characters at packet read time. + packet << (char) (0x7d ^ 0x20); + + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success) + { + StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); + if (response_type == StringExtractorGDBRemote::eResponse) + { + if (!response.Empty()) + { + // The packet has already had the 0x7d xor quoting stripped out at the + // GDBRemoteCommunication packet receive level. + object_sp = StructuredData::ParseJSON (response.GetStringRef()); + } + } + } + } + return object_sp; +} + +// Establish the largest memory read/write payloads we should use. +// If the remote stub has a max packet size, stay under that size. +// +// If the remote stub's max packet size is crazy large, use a +// reasonable largeish default. +// +// If the remote stub doesn't advertise a max packet size, use a +// conservative default. + +void +ProcessGDBRemote::GetMaxMemorySize() +{ + const uint64_t reasonable_largeish_default = 128 * 1024; + const uint64_t conservative_default = 512; + + if (m_max_memory_size == 0) + { + uint64_t stub_max_size = m_gdb_comm.GetRemoteMaxPacketSize(); + if (stub_max_size != UINT64_MAX && stub_max_size != 0) + { + // Save the stub's claimed maximum packet size + m_remote_stub_max_memory_size = stub_max_size; + + // Even if the stub says it can support ginormous packets, + // don't exceed our reasonable largeish default packet size. + if (stub_max_size > reasonable_largeish_default) + { + stub_max_size = reasonable_largeish_default; + } + + m_max_memory_size = stub_max_size; + } + else + { + m_max_memory_size = conservative_default; + } + } +} + +void +ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max) +{ + if (user_specified_max != 0) + { + GetMaxMemorySize (); + + if (m_remote_stub_max_memory_size != 0) + { + if (m_remote_stub_max_memory_size < user_specified_max) + { + m_max_memory_size = m_remote_stub_max_memory_size; // user specified a packet size too big, go as big + // as the remote stub says we can go. + } + else + { + m_max_memory_size = user_specified_max; // user's packet size is good + } + } + else + { + m_max_memory_size = user_specified_max; // user's packet size is probably fine + } + } +} class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed { @@ -3102,6 +3357,53 @@ public: } }; +class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed +{ +private: + +public: + CommandObjectProcessGDBRemotePacketXferSize(CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "process plugin packet xfer-size", + "Maximum size that lldb will try to read/write one one chunk.", + NULL) + { + } + + ~CommandObjectProcessGDBRemotePacketXferSize () + { + } + + bool + DoExecute (Args& command, CommandReturnObject &result) + { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) + { + result.AppendErrorWithFormat ("'%s' takes an argument to specify the max amount to be transferred when reading/writing", m_cmd_name.c_str()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); + if (process) + { + const char *packet_size = command.GetArgumentAtIndex(0); + errno = 0; + uint64_t user_specified_max = strtoul (packet_size, NULL, 10); + if (errno == 0 && user_specified_max != 0) + { + process->SetUserSpecifiedMaxMemoryTransferSize (user_specified_max); + result.SetStatus (eReturnStatusSuccessFinishResult); + return true; + } + } + result.SetStatus (eReturnStatusFailed); + return false; + } +}; + + class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed { private: @@ -3227,6 +3529,7 @@ public: LoadSubCommand ("history", CommandObjectSP (new CommandObjectProcessGDBRemotePacketHistory (interpreter))); LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessGDBRemotePacketSend (interpreter))); LoadSubCommand ("monitor", CommandObjectSP (new CommandObjectProcessGDBRemotePacketMonitor (interpreter))); + LoadSubCommand ("xfer-size", CommandObjectSP (new CommandObjectProcessGDBRemotePacketXferSize (interpreter))); } ~CommandObjectProcessGDBRemotePacket () diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 9331775..942b31c 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -23,7 +23,9 @@ #include "lldb/Core/Error.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/StringList.h" +#include "lldb/Core/StructuredData.h" #include "lldb/Core/ThreadSafeValue.h" +#include "lldb/lldb-private-forward.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" @@ -113,7 +115,7 @@ public: const lldb_private::ProcessAttachInfo &attach_info); virtual void - DidAttach (); + DidAttach (lldb_private::ArchSpec &process_arch); //------------------------------------------------------------------ // PluginInterface protocol @@ -221,12 +223,17 @@ public: return m_gdb_comm; } + virtual lldb_private::Error + SendEventData(const char *data); + //---------------------------------------------------------------------- // Override SetExitStatus so we can disconnect from the remote GDB server //---------------------------------------------------------------------- virtual bool SetExitStatus (int exit_status, const char *cstr); + void + SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max); protected: friend class ThreadGDBRemote; @@ -299,6 +306,15 @@ protected: bool ParseRegisters(lldb_private::ScriptInterpreterObject *registers_array); + const lldb::DataBufferSP + GetAuxvData() override; + + lldb_private::StructuredData::ObjectSP + GetExtendedInfoForThread (lldb::tid_t tid); + + void + GetMaxMemorySize(); + //------------------------------------------------------------------ /// Broadcaster event bits definitions. //------------------------------------------------------------------ @@ -334,14 +350,15 @@ protected: tid_sig_collection m_continue_C_tids; // 'C' for continue with signal tid_collection m_continue_s_tids; // 's' for step tid_sig_collection m_continue_S_tids; // 'S' for step with signal - size_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory + uint64_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory + uint64_t m_remote_stub_max_memory_size; // The maximum memory size the remote gdb stub can handle MMapMap m_addr_to_mmap_size; lldb::BreakpointSP m_thread_create_bp_sp; bool m_waiting_for_attach; bool m_destroy_tried_resuming; lldb::CommandObjectSP m_command_sp; int64_t m_breakpoint_pc_offset; - + bool StartAsyncThread (); @@ -368,7 +385,7 @@ protected: UpdateThreadIDList (); void - DidLaunchOrAttach (); + DidLaunchOrAttach (lldb_private::ArchSpec& process_arch); lldb_private::Error ConnectToDebugserver (const char *host_port); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index fb524de..5c70cb5 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -107,6 +107,58 @@ ThreadGDBRemote::GetQueueID () return LLDB_INVALID_QUEUE_ID; } +QueueSP +ThreadGDBRemote::GetQueue () +{ + queue_id_t queue_id = GetQueueID(); + QueueSP queue; + if (queue_id != LLDB_INVALID_QUEUE_ID) + { + ProcessSP process_sp (GetProcess()); + if (process_sp) + { + queue = process_sp->GetQueueList().FindQueueByID (queue_id); + } + } + return queue; +} + +addr_t +ThreadGDBRemote::GetQueueLibdispatchQueueAddress () +{ + addr_t dispatch_queue_t_addr = LLDB_INVALID_ADDRESS; + if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) + { + ProcessSP process_sp (GetProcess()); + if (process_sp) + { + SystemRuntime *runtime = process_sp->GetSystemRuntime (); + if (runtime) + { + dispatch_queue_t_addr = runtime->GetLibdispatchQueueAddressFromThreadQAddress (m_thread_dispatch_qaddr); + } + } + } + return dispatch_queue_t_addr; +} + +StructuredData::ObjectSP +ThreadGDBRemote::FetchThreadExtendedInfo () +{ + StructuredData::ObjectSP object_sp; + const lldb::user_id_t tid = GetProtocolID(); + Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD)); + if (log) + log->Printf ("Fetching extended information for thread %4.4" PRIx64, tid); + ProcessSP process_sp (GetProcess()); + if (process_sp) + { + ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); + object_sp = gdb_process->GetExtendedInfoForThread (tid); + } + return object_sp; +} + void ThreadGDBRemote::WillResume (StateType resume_state) { diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index dd4cc03..a204a91 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -12,6 +12,7 @@ #include <string> +#include "lldb/Core/StructuredData.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" @@ -41,6 +42,12 @@ public: virtual lldb::queue_id_t GetQueueID (); + virtual lldb::QueueSP + GetQueue (); + + lldb::addr_t + GetQueueLibdispatchQueueAddress (); + virtual lldb::RegisterContextSP GetRegisterContext (); @@ -80,6 +87,9 @@ public: m_thread_dispatch_qaddr = thread_dispatch_qaddr; } + lldb_private::StructuredData::ObjectSP + FetchThreadExtendedInfo (); + protected: friend class ProcessGDBRemote; |