Index: source/Plugins/Process/POSIX/CMakeLists.txt =================================================================== --- source/Plugins/Process/POSIX/CMakeLists.txt +++ source/Plugins/Process/POSIX/CMakeLists.txt @@ -10,6 +10,7 @@ ProcessMessage.cpp ProcessPOSIX.cpp ProcessPOSIXLog.cpp + RegisterContextPOSIXProcessMonitor_arm64.cpp RegisterContextPOSIXProcessMonitor_mips64.cpp RegisterContextPOSIXProcessMonitor_x86.cpp ) Index: source/Plugins/Process/POSIX/POSIXThread.cpp =================================================================== --- source/Plugins/Process/POSIX/POSIXThread.cpp +++ source/Plugins/Process/POSIX/POSIXThread.cpp @@ -30,6 +30,7 @@ #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" @@ -211,6 +212,13 @@ 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); @@ -611,6 +619,7 @@ llvm_unreachable("CPU type not supported!"); break; + case llvm::Triple::aarch64: case llvm::Triple::mips64: case llvm::Triple::x86: case llvm::Triple::x86_64: @@ -641,6 +650,7 @@ assert(false && "CPU type not supported!"); break; + case llvm::Triple::aarch64: case llvm::Triple::mips64: case llvm::Triple::x86: case llvm::Triple::x86_64: Index: source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.h =================================================================== --- /dev/null +++ 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 Index: source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm64.cpp =================================================================== --- /dev/null +++ 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(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; +} Index: source/Plugins/Process/Utility/CMakeLists.txt =================================================================== --- source/Plugins/Process/Utility/CMakeLists.txt +++ source/Plugins/Process/Utility/CMakeLists.txt @@ -27,6 +27,7 @@ RegisterContextMach_i386.cpp RegisterContextMach_x86_64.cpp RegisterContextMemory.cpp + RegisterContextPOSIX_arm64.cpp RegisterContextPOSIX_mips64.cpp RegisterContextPOSIX_x86.cpp RegisterContextThreadMemory.cpp Index: source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h =================================================================== --- /dev/null +++ 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 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_ Index: source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp =================================================================== --- /dev/null +++ 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 +#include +#include + +#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; +}