Index: source/Plugins/Process/Linux/CMakeLists.txt =================================================================== --- source/Plugins/Process/Linux/CMakeLists.txt +++ source/Plugins/Process/Linux/CMakeLists.txt @@ -7,6 +7,7 @@ add_lldb_library(lldbPluginProcessLinux LinuxThread.cpp NativeProcessLinux.cpp + NativeRegisterContextLinux_arm.cpp NativeRegisterContextLinux_arm64.cpp NativeRegisterContextLinux_x86_64.cpp NativeRegisterContextLinux_mips64.cpp Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h @@ -0,0 +1,116 @@ +//===-- NativeRegisterContextLinux_arm.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_NativeRegisterContextLinux_arm_h +#define lldb_NativeRegisterContextLinux_arm_h + +#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h" +#include "Plugins/Process/Utility/lldb-arm-register-enums.h" + +namespace lldb_private { +namespace process_linux { + + class NativeProcessLinux; + + class NativeRegisterContextLinux_arm : public NativeRegisterContextRegisterInfo + { + public: + NativeRegisterContextLinux_arm (NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p); + + uint32_t + GetRegisterSetCount () const override; + + const RegisterSet * + GetRegisterSet (uint32_t set_index) const override; + + Error + ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) override; + + Error + WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) override; + + Error + ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override; + + Error + WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override; + + private: + 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; + }; + + struct QReg + { + uint8_t bytes[16]; + }; + + struct FPU + { + union { + uint32_t s[32]; + uint64_t d[32]; + QReg q[16]; // the 128-bit NEON registers + } floats; + uint32_t fpscr; + }; + + uint32_t m_gpr_arm[k_num_gpr_registers_arm]; + RegInfo m_reg_info; + FPU m_fpr; + + bool + IsGPR(unsigned reg) const; + + bool + ReadGPR (); + + bool + WriteGPR (); + + bool + IsFPR(unsigned reg) const; + + bool + ReadFPR (); + + bool + WriteFPR (); + + Error + ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value); + + Error + WriteRegisterRaw (uint32_t reg_index, const RegisterValue ®_value); + + lldb::ByteOrder + GetByteOrder() const; + + size_t + GetGPRSize() const; + }; + +} // namespace process_linux +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextLinux_arm_h + Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -0,0 +1,520 @@ +//===-- NativeRegisterContextLinux_arm.cpp --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NativeRegisterContextLinux_arm.h" + +#include "lldb/lldb-private-forward.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "Plugins/Process/Linux/NativeProcessLinux.h" + +#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr)) + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_linux; + +// arm general purpose registers. +static const uint32_t g_gpr_regnums_arm[] = +{ + gpr_r0_arm, + gpr_r1_arm, + gpr_r2_arm, + gpr_r3_arm, + gpr_r4_arm, + gpr_r5_arm, + gpr_r6_arm, + gpr_r7_arm, + gpr_r8_arm, + gpr_r9_arm, + gpr_r10_arm, + gpr_r11_arm, + gpr_r12_arm, + gpr_sp_arm, + gpr_lr_arm, + gpr_pc_arm, + gpr_cpsr_arm, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == k_num_gpr_registers_arm, \ + "g_gpr_regnums_arm has wrong number of register infos"); + +// arm floating point registers. +static const uint32_t g_fpu_regnums_arm[] = +{ + fpu_s0_arm, + fpu_s1_arm, + fpu_s2_arm, + fpu_s3_arm, + fpu_s4_arm, + fpu_s5_arm, + fpu_s6_arm, + fpu_s7_arm, + fpu_s8_arm, + fpu_s9_arm, + fpu_s10_arm, + fpu_s11_arm, + fpu_s12_arm, + fpu_s13_arm, + fpu_s14_arm, + fpu_s15_arm, + fpu_s16_arm, + fpu_s17_arm, + fpu_s18_arm, + fpu_s19_arm, + fpu_s20_arm, + fpu_s21_arm, + fpu_s22_arm, + fpu_s23_arm, + fpu_s24_arm, + fpu_s25_arm, + fpu_s26_arm, + fpu_s27_arm, + fpu_s28_arm, + fpu_s29_arm, + fpu_s30_arm, + fpu_s31_arm, + fpu_fpscr_arm, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \ + "g_fpu_regnums_arm has wrong number of register infos"); + +namespace { + // Number of register sets provided by this context. + enum + { + k_num_register_sets = 2 + }; +} + +// Register sets for arm. +static const RegisterSet +g_reg_sets_arm[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm } +}; + +NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm ( + NativeThreadProtocol &native_thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *reg_info_interface_p) : + NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p) +{ + switch (reg_info_interface_p->m_target_arch.GetMachine()) + { + case llvm::Triple::arm: + m_reg_info.num_registers = k_num_registers_arm; + m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; + m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; + m_reg_info.last_gpr = k_last_gpr_arm; + m_reg_info.first_fpr = k_first_fpr_arm; + m_reg_info.last_fpr = k_last_fpr_arm; + m_reg_info.first_fpr_v = fpu_s0_arm; + m_reg_info.last_fpr_v = fpu_s31_arm; + m_reg_info.gpr_flags = gpr_cpsr_arm; + break; + default: + assert(false && "Unhandled target architecture."); + break; + } + + ::memset(&m_fpr, 0, sizeof (m_fpr)); + ::memset(&m_gpr_arm, 0, sizeof (m_gpr_arm)); +} + +uint32_t +NativeRegisterContextLinux_arm::GetRegisterSetCount () const +{ + return k_num_register_sets; +} + +const RegisterSet * +NativeRegisterContextLinux_arm::GetRegisterSet (uint32_t set_index) const +{ + if (set_index < k_num_register_sets) + return &g_reg_sets_arm[set_index]; + + return nullptr; +} + +Error +NativeRegisterContextLinux_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) +{ + Error error; + + if (!reg_info) + { + error.SetErrorString ("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsFPR(reg)) + { + if (!ReadFPR()) + { + error.SetErrorString ("failed to read floating point register"); + return error; + } + } + 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]; + } + + error = ReadRegisterRaw(full_reg, reg_value); + + if (error.Success ()) + { + // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. + if (is_subreg && (reg_info->byte_offset & 0x1)) + reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); + + // If our return byte size was greater than the return value reg size, then + // use the type specified by reg_info rather than the uint64_t default + if (reg_value.GetByteSize() > reg_info->byte_size) + reg_value.SetType(reg_info); + } + return error; + } + + // 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: + reg_value.SetUInt16(*(uint16_t *)src); + break; + case 4: + reg_value.SetUInt32(*(uint32_t *)src); + break; + case 8: + reg_value.SetUInt64(*(uint64_t *)src); + break; + default: + assert(false && "Unhandled data size."); + error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size); + break; + } + + return error; +} + +Error +NativeRegisterContextLinux_arm::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) +{ + if (!reg_info) + return Error ("reg_info NULL"); + + const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg_index == LLDB_INVALID_REGNUM) + return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : ""); + + if (IsGPR(reg_index)) + return WriteRegisterRaw(reg_index, reg_value); + + if (IsFPR(reg_index)) + { + // Get pointer to m_fpr variable and set the data to it. + assert (reg_info->byte_offset < sizeof(m_fpr)); + uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 2: + *(uint16_t *)dst = reg_value.GetAsUInt16(); + break; + case 4: + *(uint32_t *)dst = reg_value.GetAsUInt32(); + break; + case 8: + *(uint64_t *)dst = reg_value.GetAsUInt64(); + break; + default: + assert(false && "Unhandled data size."); + return Error ("unhandled register data size %" PRIu32, reg_info->byte_size); + } + + if (!WriteFPR()) + { + return Error ("NativeRegisterContextLinux_arm::WriteRegister: WriteFPR failed"); + } + + return Error (); + } + + return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown"); +} + +Error +NativeRegisterContextLinux_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) +{ + Error error; + + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (!data_sp) + return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE); + + if (!ReadGPR ()) + { + error.SetErrorString ("ReadGPR() failed"); + return error; + } + + if (!ReadFPR ()) + { + error.SetErrorString ("ReadFPR() failed"); + return error; + } + + uint8_t *dst = data_sp->GetBytes (); + if (dst == nullptr) + { + error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE); + return error; + } + + ::memcpy (dst, &m_gpr_arm, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy (dst, &m_fpr, sizeof(m_fpr)); + + return error; +} + +Error +NativeRegisterContextLinux_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) +{ + Error error; + + if (!data_sp) + { + error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) + { + error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ()); + return error; + } + + + uint8_t *src = data_sp->GetBytes (); + if (src == nullptr) + { + error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); + return error; + } + ::memcpy (&m_gpr_arm, src, GetRegisterInfoInterface ().GetGPRSize ()); + + if (!WriteGPR ()) + { + error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__); + return error; + } + + src += GetRegisterInfoInterface ().GetGPRSize (); + ::memcpy (&m_fpr, src, sizeof(m_fpr)); + + if (!WriteFPR ()) + { + error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__); + return error; + } + + return error; +} + +Error +NativeRegisterContextLinux_arm::WriteRegisterRaw (uint32_t reg_index, const RegisterValue ®_value) +{ + Error error; + + uint32_t reg_to_write = reg_index; + RegisterValue value_to_write = reg_value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + error = ReadRegister(full_reg_info, full_value); + if (error.Fail ()) + return error; + + lldb::ByteOrder byte_order = GetByteOrder(); + uint8_t dst[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[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = reg_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; + } + } + } + + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + { + error.SetErrorString ("NativeProcessProtocol is NULL"); + return error; + } + + const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write); + assert (register_to_write_info_p && "register to write does not have valid RegisterInfo"); + if (!register_to_write_info_p) + { + error.SetErrorStringWithFormat ("NativeRegisterContextLinux_arm::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write); + return error; + } + + NativeProcessLinux *const process_p = reinterpret_cast (process_sp.get ()); + return process_p->WriteRegisterValue(m_thread.GetID(), + register_to_write_info_p->byte_offset, + register_to_write_info_p->name, + value_to_write); +} + +Error +NativeRegisterContextLinux_arm::ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value) +{ + Error error; + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index); + if (!reg_info) + { + error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index); + return error; + } + + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + { + error.SetErrorString ("NativeProcessProtocol is NULL"); + return error; + } + + NativeProcessLinux *const process_p = reinterpret_cast (process_sp.get ()); + return process_p->ReadRegisterValue(m_thread.GetID(), + reg_info->byte_offset, + reg_info->name, + reg_info->byte_size, + reg_value); +} + +bool +NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const +{ + return reg <= m_reg_info.last_gpr; // GPR's come first. +} + +bool +NativeRegisterContextLinux_arm::ReadGPR() +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + return false; + NativeProcessLinux *const process_p = reinterpret_cast (process_sp.get ()); + + return process_p->ReadGPR (m_thread.GetID (), &m_gpr_arm, GetRegisterInfoInterface ().GetGPRSize ()).Success(); +} + +bool +NativeRegisterContextLinux_arm::WriteGPR() +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + return false; + NativeProcessLinux *const process_p = reinterpret_cast (process_sp.get ()); + + return process_p->WriteGPR (m_thread.GetID (), &m_gpr_arm, GetRegisterInfoInterface ().GetGPRSize ()).Success(); +} + +bool +NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const +{ + return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); +} + +bool +NativeRegisterContextLinux_arm::ReadFPR () +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + return false; + + NativeProcessLinux *const process_p = reinterpret_cast (process_sp.get ()); + return process_p->ReadFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success(); +} + +bool +NativeRegisterContextLinux_arm::WriteFPR () +{ + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + return false; + + NativeProcessLinux *const process_p = reinterpret_cast (process_sp.get ()); + return process_p->WriteFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success(); +} + +lldb::ByteOrder +NativeRegisterContextLinux_arm::GetByteOrder() const +{ + // Get the target process whose privileged thread was used for the register read. + lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; + + NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); + if (!process_sp) + return byte_order; + + if (!process_sp->GetByteOrder (byte_order)) + { + // FIXME log here + } + + return byte_order; +} + +size_t +NativeRegisterContextLinux_arm::GetGPRSize() const +{ + return GetRegisterInfoInterface().GetGPRSize(); +} Index: source/Plugins/Process/Linux/NativeThreadLinux.cpp =================================================================== --- source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -13,6 +13,7 @@ #include #include "NativeProcessLinux.h" +#include "NativeRegisterContextLinux_arm.h" #include "NativeRegisterContextLinux_arm64.h" #include "NativeRegisterContextLinux_x86_64.h" #include "NativeRegisterContextLinux_mips64.h" @@ -29,6 +30,7 @@ #include "Plugins/Process/POSIX/CrashReason.h" +#include "Plugins/Process/Utility/RegisterContextLinux_arm.h" #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" #include "Plugins/Process/Utility/RegisterContextLinux_i386.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" @@ -184,6 +186,10 @@ assert((HostInfo::GetArchitecture ().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); reg_interface = static_cast(new RegisterContextLinux_arm64(target_arch)); break; + case llvm::Triple::arm: + assert(HostInfo::GetArchitecture ().GetAddressByteSize() == 4); + reg_interface = static_cast(new RegisterContextLinux_arm(target_arch)); + break; case llvm::Triple::x86: case llvm::Triple::x86_64: if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) @@ -242,6 +248,12 @@ m_reg_context_sp.reset (new NativeRegisterContextLinux_arm64(*this, concrete_frame_idx, reg_interface)); break; } + case llvm::Triple::arm: + { + const uint32_t concrete_frame_idx = 0; + m_reg_context_sp.reset (new NativeRegisterContextLinux_arm(*this, concrete_frame_idx, reg_interface)); + break; + } case llvm::Triple::x86: case llvm::Triple::x86_64: { Index: source/Plugins/Process/POSIX/CMakeLists.txt =================================================================== --- source/Plugins/Process/POSIX/CMakeLists.txt +++ source/Plugins/Process/POSIX/CMakeLists.txt @@ -11,6 +11,7 @@ ProcessMessage.cpp ProcessPOSIX.cpp ProcessPOSIXLog.cpp + RegisterContextPOSIXProcessMonitor_arm.cpp RegisterContextPOSIXProcessMonitor_arm64.cpp RegisterContextPOSIXProcessMonitor_mips64.cpp RegisterContextPOSIXProcessMonitor_powerpc.cpp Index: source/Plugins/Process/POSIX/POSIXThread.cpp =================================================================== --- source/Plugins/Process/POSIX/POSIXThread.cpp +++ source/Plugins/Process/POSIX/POSIXThread.cpp @@ -32,10 +32,12 @@ #include "ProcessPOSIX.h" #include "ProcessPOSIXLog.h" #include "Plugins/Process/Linux/ProcessMonitor.h" +#include "RegisterContextPOSIXProcessMonitor_arm.h" #include "RegisterContextPOSIXProcessMonitor_arm64.h" #include "RegisterContextPOSIXProcessMonitor_mips64.h" #include "RegisterContextPOSIXProcessMonitor_powerpc.h" #include "RegisterContextPOSIXProcessMonitor_x86.h" +#include "Plugins/Process/Utility/RegisterContextLinux_arm.h" #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" #include "Plugins/Process/Utility/RegisterContextLinux_i386.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" @@ -198,6 +200,10 @@ assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); reg_interface = static_cast(new RegisterContextLinux_arm64(target_arch)); break; + case llvm::Triple::arm: + assert(HostInfo::GetArchitecture().GetAddressByteSize() == 4); + reg_interface = static_cast(new RegisterContextLinux_arm(target_arch)); + break; case llvm::Triple::x86: case llvm::Triple::x86_64: if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) @@ -232,6 +238,13 @@ m_reg_context_sp.reset(reg_ctx); break; } + case llvm::Triple::arm: + { + RegisterContextPOSIXProcessMonitor_arm *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm(*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); @@ -641,6 +654,7 @@ break; case llvm::Triple::aarch64: + case llvm::Triple::arm: case llvm::Triple::mips64: case llvm::Triple::ppc: case llvm::Triple::ppc64: @@ -674,6 +688,7 @@ break; case llvm::Triple::aarch64: + case llvm::Triple::arm: case llvm::Triple::mips64: case llvm::Triple::ppc: case llvm::Triple::ppc64: Index: source/Plugins/Process/POSIX/ProcessPOSIX.cpp =================================================================== --- source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -14,6 +14,7 @@ // C++ Includes // Other libraries and framework includes +#include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" @@ -638,6 +639,33 @@ assert(false && "CPU type not supported!"); break; + case llvm::Triple::arm: + { + // The ARM reference recommends the use of 0xe7fddefe and 0xdefe + // but the linux kernel does otherwise. + static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 }; + static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde }; + + lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0)); + AddressClass addr_class = eAddressClassUnknown; + + if (bp_loc_sp) + addr_class = bp_loc_sp->GetAddress ().GetAddressClass (); + + if (addr_class == eAddressClassCodeAlternateISA + || (addr_class == eAddressClassUnknown + && bp_loc_sp->GetAddress().GetOffset() & 1)) + { + opcode = g_thumb_breakpoint_opcode; + opcode_size = sizeof(g_thumb_breakpoint_opcode); + } + else + { + opcode = g_arm_breakpoint_opcode; + opcode_size = sizeof(g_arm_breakpoint_opcode); + } + } + break; case llvm::Triple::aarch64: opcode = g_aarch64_opcode; opcode_size = sizeof(g_aarch64_opcode); Index: source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm.h =================================================================== --- source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm.h +++ source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm.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_arm_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_arm_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h" + +class RegisterContextPOSIXProcessMonitor_arm: + public RegisterContextPOSIX_arm, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_arm(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_arm.cpp =================================================================== --- source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm.cpp +++ source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_arm.cpp @@ -0,0 +1,322 @@ +//===-- RegisterContextPOSIXProcessMonitor_arm.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/Core/DataBufferHeap.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" + +#include "RegisterContextPOSIX_arm.h" +#include "ProcessPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_arm.h" +#include "ProcessMonitor.h" + +using namespace lldb_private; +using namespace lldb; + +#define REG_CONTEXT_SIZE (GetGPRSize()) + +RegisterContextPOSIXProcessMonitor_arm::RegisterContextPOSIXProcessMonitor_arm(Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_arm(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_arm::GetMonitor() +{ + ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const unsigned reg, + RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const unsigned reg, + const RegisterValue &value) +{ + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[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[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_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg)) + { + if (!ReadFPR()) + return false; + } + else + { + return ReadRegister(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_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsGPR(reg)) + { + return WriteRegister(reg, value); + } + else if (IsFPR(reg)) + { + return WriteFPR(); + } + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ReadAllRegisterValues(DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new 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_arm, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy (dst, &m_fpr, sizeof(m_fpr)); + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::WriteAllRegisterValues(const 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_arm, src, GetGPRSize()); + + if (WriteGPR()) + { + src += GetGPRSize(); + ::memcpy (&m_fpr, src, sizeof(m_fpr)); + + success = WriteFPR(); + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpoint(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_arm::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::UpdateAfterBreakpoint() +{ + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_arm::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < k_num_registers_arm; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_arm && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::IsWatchpointHit(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::ClearWatchpointHits() +{ + return false; +} + +addr_t +RegisterContextPOSIXProcessMonitor_arm::GetWatchpointAddress(uint32_t hw_index) +{ + return LLDB_INVALID_ADDRESS; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::IsWatchpointVacant(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_arm::NumSupportedHardwareWatchpoints() +{ + return 0; +} + Index: source/Plugins/Process/Utility/CMakeLists.txt =================================================================== --- source/Plugins/Process/Utility/CMakeLists.txt +++ source/Plugins/Process/Utility/CMakeLists.txt @@ -20,6 +20,7 @@ RegisterContextFreeBSD_powerpc.cpp RegisterContextFreeBSD_x86_64.cpp RegisterContextHistory.cpp + RegisterContextLinux_arm.cpp RegisterContextLinux_arm64.cpp RegisterContextLinux_i386.cpp RegisterContextLinux_x86_64.cpp @@ -30,6 +31,7 @@ RegisterContextMach_i386.cpp RegisterContextMach_x86_64.cpp RegisterContextMemory.cpp + RegisterContextPOSIX_arm.cpp RegisterContextPOSIX_arm64.cpp RegisterContextPOSIX_mips64.cpp RegisterContextPOSIX_powerpc.cpp Index: source/Plugins/Process/Utility/RegisterContextLinux_arm.h =================================================================== --- source/Plugins/Process/Utility/RegisterContextLinux_arm.h +++ source/Plugins/Process/Utility/RegisterContextLinux_arm.h @@ -0,0 +1,76 @@ +//===-- RegisterContextLinux_arm.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_arm_h_ +#define liblldb_RegisterContextLinux_arm_h_ + +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" +#include "RegisterContextPOSIX.h" +#include "RegisterInfoInterface.h" + +class RegisterContextLinux_arm + : public lldb_private::RegisterInfoInterface +{ +public: + + struct GPR + { + uint32_t r[16]; // R0-R15 + uint32_t cpsr; // CPSR + }; + + + struct QReg + { + uint8_t bytes[16]; + }; + + struct FPU + { + union { + uint32_t s[32]; + uint64_t d[32]; + QReg q[16]; // the 128-bit NEON registers + } floats; + uint32_t fpscr; + }; + struct EXC + { + uint32_t exception; + uint32_t fsr; /* Fault status */ + uint32_t far; /* Virtual Fault Address */ + }; + + struct DBG + { + uint32_t bvr[16]; + uint32_t bcr[16]; + uint32_t wvr[16]; + uint32_t wcr[16]; + }; + + RegisterContextLinux_arm(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 // liblldb_RegisterContextLinux_arm_h_ + Index: source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp =================================================================== --- source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp +++ source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp @@ -0,0 +1,87 @@ +//===-- RegisterContextLinux_arm.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 "llvm/Support/Compiler.h" +#include "lldb/lldb-defines.h" + +#include "RegisterContextLinux_arm.h" + +using namespace lldb; +using namespace lldb_private; + +// Based on RegisterContextDarwin_arm.cpp +#define GPR_OFFSET(idx) ((idx) * 4) +#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR)) +#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU)) +#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextLinux_arm::DBG, reg) + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC))) + +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(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 (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC)) + +//----------------------------------------------------------------------------- +// Include RegisterInfos_arm to declare our g_register_infos_arm structure. +//----------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_ARM_STRUCT +#include "RegisterInfos_arm.h" +#undef DECLARE_REGISTER_INFOS_ARM_STRUCT + +static const lldb_private::RegisterInfo * +GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch) +{ + switch (target_arch.GetMachine()) + { + case llvm::Triple::arm: + return g_register_infos_arm; + 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::arm: + return static_cast(sizeof(g_register_infos_arm) / sizeof(g_register_infos_arm[0])); + default: + assert(false && "Unhandled target architecture."); + return 0; + } +} + +RegisterContextLinux_arm::RegisterContextLinux_arm(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_arm::GetGPRSize() const +{ + return sizeof(struct RegisterContextLinux_arm::GPR); +} + +const lldb_private::RegisterInfo * +RegisterContextLinux_arm::GetRegisterInfo() const +{ + return m_register_info_p; +} + +uint32_t +RegisterContextLinux_arm::GetRegisterCount() const +{ + return m_register_info_count; +} Index: source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h =================================================================== --- source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h +++ source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h @@ -0,0 +1,121 @@ +//===-- RegisterContextPOSIX_arm.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_arm_H_ +#define liblldb_RegisterContextPOSIX_arm_H_ + +#include "lldb/Core/Log.h" +#include "lldb-arm-register-enums.h" +#include "RegisterContextPOSIX.h" + +class ProcessMonitor; + +class RegisterContextPOSIX_arm + : public lldb_private::RegisterContext +{ +public: + RegisterContextPOSIX_arm (lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); + + ~RegisterContextPOSIX_arm(); + + 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; + }; + + struct QReg + { + uint8_t bytes[16]; + }; + + struct FPU + { + union { + uint32_t s[32]; + uint64_t d[32]; + QReg q[16]; // the 128-bit NEON registers + } floats; + uint32_t fpscr; + }; + + uint32_t m_gpr_arm[lldb_private::k_num_gpr_registers_arm]; // 32-bit general purpose registers. + RegInfo m_reg_info; + struct RegisterContextPOSIX_arm::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_arm_H_ + Index: source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp =================================================================== --- source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp +++ source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp @@ -0,0 +1,287 @@ +//===-- RegisterContextPOSIX_arm.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_arm.h" +#include "Plugins/Process/elf-core/ProcessElfCore.h" + +using namespace lldb; +using namespace lldb_private; + +// arm general purpose registers. +const uint32_t g_gpr_regnums_arm[] = +{ + gpr_r0_arm, + gpr_r1_arm, + gpr_r2_arm, + gpr_r3_arm, + gpr_r4_arm, + gpr_r5_arm, + gpr_r6_arm, + gpr_r7_arm, + gpr_r8_arm, + gpr_r9_arm, + gpr_r10_arm, + gpr_r11_arm, + gpr_r12_arm, + gpr_sp_arm, + gpr_lr_arm, + gpr_pc_arm, + gpr_cpsr_arm, + LLDB_INVALID_REGNUM // register sets need to end with this flag + +}; +static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == k_num_gpr_registers_arm, \ + "g_gpr_regnums_arm has wrong number of register infos"); + +// arm floating point registers. +static const uint32_t g_fpu_regnums_arm[] = +{ + fpu_s0_arm, + fpu_s1_arm, + fpu_s2_arm, + fpu_s3_arm, + fpu_s4_arm, + fpu_s5_arm, + fpu_s6_arm, + fpu_s7_arm, + fpu_s8_arm, + fpu_s9_arm, + fpu_s10_arm, + fpu_s11_arm, + fpu_s12_arm, + fpu_s13_arm, + fpu_s14_arm, + fpu_s15_arm, + fpu_s16_arm, + fpu_s17_arm, + fpu_s18_arm, + fpu_s19_arm, + fpu_s20_arm, + fpu_s21_arm, + fpu_s22_arm, + fpu_s23_arm, + fpu_s24_arm, + fpu_s25_arm, + fpu_s26_arm, + fpu_s27_arm, + fpu_s28_arm, + fpu_s29_arm, + fpu_s30_arm, + fpu_s31_arm, + fpu_fpscr_arm, + LLDB_INVALID_REGNUM // register sets need to end with this flag + +}; +static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \ + "g_fpu_regnums_arm has wrong number of register infos"); + +// Number of register sets provided by this context. +enum +{ + k_num_register_sets = 2 +}; + +// Register sets for arm. +static const lldb_private::RegisterSet +g_reg_sets_arm[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm } +}; + +bool RegisterContextPOSIX_arm::IsGPR(unsigned reg) +{ + return reg <= m_reg_info.last_gpr; // GPR's come first. +} + +bool RegisterContextPOSIX_arm::IsFPR(unsigned reg) +{ + return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); +} + +RegisterContextPOSIX_arm::RegisterContextPOSIX_arm(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::arm: + m_reg_info.num_registers = k_num_registers_arm; + m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; + m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; + m_reg_info.last_gpr = k_last_gpr_arm; + m_reg_info.first_fpr = k_first_fpr_arm; + m_reg_info.last_fpr = k_last_fpr_arm; + m_reg_info.first_fpr_v = fpu_s0_arm; + m_reg_info.last_fpr_v = fpu_s31_arm; + m_reg_info.gpr_flags = gpr_cpsr_arm; + 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_arm::~RegisterContextPOSIX_arm() +{ +} + +void +RegisterContextPOSIX_arm::Invalidate() +{ +} + +void +RegisterContextPOSIX_arm::InvalidateAllRegisters() +{ +} + +unsigned +RegisterContextPOSIX_arm::GetRegisterOffset(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_offset; +} + +unsigned +RegisterContextPOSIX_arm::GetRegisterSize(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_size; +} + +size_t +RegisterContextPOSIX_arm::GetRegisterCount() +{ + size_t num_registers = m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers; + return num_registers; +} + +size_t +RegisterContextPOSIX_arm::GetGPRSize() +{ + return m_register_info_ap->GetGPRSize (); +} + +const lldb_private::RegisterInfo * +RegisterContextPOSIX_arm::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_arm::GetRegisterInfoAtIndex(size_t reg) +{ + if (reg < m_reg_info.num_registers) + return &GetRegisterInfo()[reg]; + else + return NULL; +} + +size_t +RegisterContextPOSIX_arm::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_arm::GetRegisterSet(size_t set) +{ + if (IsRegisterSetAvailable(set)) + { + switch (m_register_info_ap->m_target_arch.GetMachine()) + { + case llvm::Triple::aarch64: + return &g_reg_sets_arm[set]; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } + } + return NULL; +} + +const char * +RegisterContextPOSIX_arm::GetRegisterName(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register offset."); + return GetRegisterInfo()[reg].name; +} + +lldb::ByteOrder +RegisterContextPOSIX_arm::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_arm::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_arm::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; +} + Index: source/Plugins/Process/Utility/RegisterInfos_arm.h =================================================================== --- source/Plugins/Process/Utility/RegisterInfos_arm.h +++ source/Plugins/Process/Utility/RegisterInfos_arm.h @@ -0,0 +1,303 @@ +//===-- RegisterInfos_arm.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_ARM_STRUCT + +#include + +#include "lldb/lldb-private.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" + +#include "Utility/ARM_GCC_Registers.h" +#include "Utility/ARM_DWARF_Registers.h" + +using namespace lldb; +using namespace lldb_private; + +#ifndef GPR_OFFSET +#error GPR_OFFSET 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 EXC_OFFSET +#error EXC_OFFSET_NAME must be defined before including this header file +#endif + +#ifndef DBG_OFFSET +#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_r0 = 0, + gpr_r1, + gpr_r2, + gpr_r3, + gpr_r4, + gpr_r5, + gpr_r6, + gpr_r7, + gpr_r8, + gpr_r9, + gpr_r10, + gpr_r11, + gpr_r12, + gpr_r13, gpr_sp = gpr_r13, + gpr_r14, gpr_lr = gpr_r14, + gpr_r15, gpr_pc = gpr_r15, + gpr_cpsr, + + fpu_s0, + fpu_s1, + fpu_s2, + fpu_s3, + fpu_s4, + fpu_s5, + fpu_s6, + fpu_s7, + fpu_s8, + fpu_s9, + fpu_s10, + fpu_s11, + fpu_s12, + fpu_s13, + fpu_s14, + fpu_s15, + fpu_s16, + fpu_s17, + fpu_s18, + fpu_s19, + fpu_s20, + fpu_s21, + fpu_s22, + fpu_s23, + fpu_s24, + fpu_s25, + fpu_s26, + fpu_s27, + fpu_s28, + fpu_s29, + fpu_s30, + fpu_s31, + fpu_fpscr, + + exc_exception, + exc_fsr, + exc_far, + + 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 RegisterInfo g_register_infos_arm[] = { +// General purpose registers +// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS +// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== =============== +{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1, gdb_arm_r0, gpr_r0 }, NULL, NULL}, +{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2, gdb_arm_r1, gpr_r1 }, NULL, NULL}, +{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3, gdb_arm_r2, gpr_r2 }, NULL, NULL}, +{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4, gdb_arm_r3, gpr_r3 }, NULL, NULL}, +{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, gpr_r4 }, NULL, NULL}, +{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, gpr_r5 }, NULL, NULL}, +{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, gpr_r6 }, NULL, NULL}, +{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_INVALID_REGNUM, gdb_arm_r7, gpr_r7 }, NULL, NULL}, +{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, gpr_r8 }, NULL, NULL}, +{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, gpr_r9 }, NULL, NULL}, +{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, gpr_r10 }, NULL, NULL}, +{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, gdb_arm_r11, gpr_r11 }, NULL, NULL}, +{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, gpr_r12 }, NULL, NULL}, +{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, gpr_sp }, NULL, NULL}, +{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, gpr_lr }, NULL, NULL}, +{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, gpr_pc }, NULL, NULL}, +{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, gpr_cpsr }, NULL, NULL}, + +{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, fpu_s0 }, NULL, NULL}, +{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, fpu_s1 }, NULL, NULL}, +{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, fpu_s2 }, NULL, NULL}, +{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, fpu_s3 }, NULL, NULL}, +{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, fpu_s4 }, NULL, NULL}, +{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, fpu_s5 }, NULL, NULL}, +{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, fpu_s6 }, NULL, NULL}, +{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, fpu_s7 }, NULL, NULL}, +{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, fpu_s8 }, NULL, NULL}, +{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, fpu_s9 }, NULL, NULL}, +{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, fpu_s10 }, NULL, NULL}, +{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, fpu_s11 }, NULL, NULL}, +{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, fpu_s12 }, NULL, NULL}, +{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, fpu_s13 }, NULL, NULL}, +{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, fpu_s14 }, NULL, NULL}, +{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, fpu_s15 }, NULL, NULL}, +{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, fpu_s16 }, NULL, NULL}, +{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, fpu_s17 }, NULL, NULL}, +{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, fpu_s18 }, NULL, NULL}, +{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, fpu_s19 }, NULL, NULL}, +{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, fpu_s20 }, NULL, NULL}, +{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, fpu_s21 }, NULL, NULL}, +{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, fpu_s22 }, NULL, NULL}, +{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, fpu_s23 }, NULL, NULL}, +{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, fpu_s24 }, NULL, NULL}, +{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, fpu_s25 }, NULL, NULL}, +{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, fpu_s26 }, NULL, NULL}, +{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, fpu_s27 }, NULL, NULL}, +{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, fpu_s28 }, NULL, NULL}, +{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, fpu_s29 }, NULL, NULL}, +{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, fpu_s30 }, NULL, NULL}, +{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, fpu_s31 }, NULL, NULL}, +{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, fpu_fpscr }, NULL, NULL}, + +{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL}, +{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, NULL, NULL}, +{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, 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_ARM_STRUCT Index: source/Plugins/Process/Utility/lldb-arm-register-enums.h =================================================================== --- source/Plugins/Process/Utility/lldb-arm-register-enums.h +++ source/Plugins/Process/Utility/lldb-arm-register-enums.h @@ -0,0 +1,153 @@ +//===-- lldb-arm-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_arm_register_enums_h +#define lldb_arm_register_enums_h + +namespace lldb_private +{ + // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) + + //--------------------------------------------------------------------------- + // Internal codes for all ARM registers. + //--------------------------------------------------------------------------- + enum + { + k_first_gpr_arm = 0, + gpr_r0_arm = k_first_gpr_arm, + gpr_r1_arm, + gpr_r2_arm, + gpr_r3_arm, + gpr_r4_arm, + gpr_r5_arm, + gpr_r6_arm, + gpr_r7_arm, + gpr_r8_arm, + gpr_r9_arm, + gpr_r10_arm, + gpr_r11_arm, + gpr_r12_arm, + gpr_r13_arm, gpr_sp_arm = gpr_r13_arm, + gpr_r14_arm, gpr_lr_arm = gpr_r14_arm, + gpr_r15_arm, gpr_pc_arm = gpr_r15_arm, + gpr_cpsr_arm, + + k_last_gpr_arm = gpr_cpsr_arm, + + k_first_fpr_arm, + fpu_s0_arm = k_first_fpr_arm, + fpu_s1_arm, + fpu_s2_arm, + fpu_s3_arm, + fpu_s4_arm, + fpu_s5_arm, + fpu_s6_arm, + fpu_s7_arm, + fpu_s8_arm, + fpu_s9_arm, + fpu_s10_arm, + fpu_s11_arm, + fpu_s12_arm, + fpu_s13_arm, + fpu_s14_arm, + fpu_s15_arm, + fpu_s16_arm, + fpu_s17_arm, + fpu_s18_arm, + fpu_s19_arm, + fpu_s20_arm, + fpu_s21_arm, + fpu_s22_arm, + fpu_s23_arm, + fpu_s24_arm, + fpu_s25_arm, + fpu_s26_arm, + fpu_s27_arm, + fpu_s28_arm, + fpu_s29_arm, + fpu_s30_arm, + fpu_s31_arm, + fpu_fpscr_arm, + k_last_fpr_arm = fpu_fpscr_arm, + exc_exception_arm, + exc_fsr_arm, + exc_far_arm, + + dbg_bvr0_arm, + dbg_bvr1_arm, + dbg_bvr2_arm, + dbg_bvr3_arm, + dbg_bvr4_arm, + dbg_bvr5_arm, + dbg_bvr6_arm, + dbg_bvr7_arm, + dbg_bvr8_arm, + dbg_bvr9_arm, + dbg_bvr10_arm, + dbg_bvr11_arm, + dbg_bvr12_arm, + dbg_bvr13_arm, + dbg_bvr14_arm, + dbg_bvr15_arm, + dbg_bcr0_arm, + dbg_bcr1_arm, + dbg_bcr2_arm, + dbg_bcr3_arm, + dbg_bcr4_arm, + dbg_bcr5_arm, + dbg_bcr6_arm, + dbg_bcr7_arm, + dbg_bcr8_arm, + dbg_bcr9_arm, + dbg_bcr10_arm, + dbg_bcr11_arm, + dbg_bcr12_arm, + dbg_bcr13_arm, + dbg_bcr14_arm, + dbg_bcr15_arm, + dbg_wvr0_arm, + dbg_wvr1_arm, + dbg_wvr2_arm, + dbg_wvr3_arm, + dbg_wvr4_arm, + dbg_wvr5_arm, + dbg_wvr6_arm, + dbg_wvr7_arm, + dbg_wvr8_arm, + dbg_wvr9_arm, + dbg_wvr10_arm, + dbg_wvr11_arm, + dbg_wvr12_arm, + dbg_wvr13_arm, + dbg_wvr14_arm, + dbg_wvr15_arm, + dbg_wcr0_arm, + dbg_wcr1_arm, + dbg_wcr2_arm, + dbg_wcr3_arm, + dbg_wcr4_arm, + dbg_wcr5_arm, + dbg_wcr6_arm, + dbg_wcr7_arm, + dbg_wcr8_arm, + dbg_wcr9_arm, + dbg_wcr10_arm, + dbg_wcr11_arm, + dbg_wcr12_arm, + dbg_wcr13_arm, + dbg_wcr14_arm, + dbg_wcr15_arm, + + k_num_registers_arm, + k_num_gpr_registers_arm = k_last_gpr_arm - k_first_gpr_arm + 1, + k_num_fpr_registers_arm = k_last_fpr_arm - k_first_fpr_arm + 1 + }; +} + +#endif // #ifndef lldb_arm64_register_enums_h Index: source/Plugins/Process/elf-core/CMakeLists.txt =================================================================== --- source/Plugins/Process/elf-core/CMakeLists.txt +++ source/Plugins/Process/elf-core/CMakeLists.txt @@ -5,6 +5,7 @@ add_lldb_library(lldbPluginProcessElfCore ProcessElfCore.cpp ThreadElfCore.cpp + RegisterContextPOSIXCore_arm.cpp RegisterContextPOSIXCore_arm64.cpp RegisterContextPOSIXCore_mips64.cpp RegisterContextPOSIXCore_powerpc.cpp Index: source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h =================================================================== --- source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h +++ source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h @@ -0,0 +1,60 @@ +//===-- RegisterContextCorePOSIX_arm.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_RegisterContextCorePOSIX_arm_H_ +#define liblldb_RegisterContextCorePOSIX_arm_H_ + +#include "lldb/Core/DataBufferHeap.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h" + +class RegisterContextCorePOSIX_arm : + public RegisterContextPOSIX_arm +{ +public: + RegisterContextCorePOSIX_arm (lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset, + const lldb_private::DataExtractor &fpregset); + + ~RegisterContextCorePOSIX_arm(); + + 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); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + bool + HardwareSingleStep(bool enable); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb_private::DataExtractor m_gpr; +}; + +#endif // #ifndef liblldb_RegisterContextCorePOSIX_arm_H_ Index: source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp =================================================================== --- source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp +++ source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp @@ -0,0 +1,94 @@ +//===-- RegisterContextCorePOSIX_arm.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/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX.h" +#include "RegisterContextPOSIXCore_arm.h" + +using namespace lldb_private; + +RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm(Thread &thread, + RegisterInfoInterface *register_info, + const DataExtractor &gpregset, + const DataExtractor &fpregset) + : RegisterContextPOSIX_arm(thread, 0, register_info) +{ + m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize())); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); +} + +RegisterContextCorePOSIX_arm::~RegisterContextCorePOSIX_arm() +{ +} + +bool +RegisterContextCorePOSIX_arm::ReadGPR() +{ + return true; +} + +bool +RegisterContextCorePOSIX_arm::ReadFPR() +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm::WriteGPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_arm::WriteFPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + 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 +RegisterContextCorePOSIX_arm::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_arm::HardwareSingleStep(bool enable) +{ + return false; +} Index: source/Plugins/Process/elf-core/ThreadElfCore.cpp =================================================================== --- source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -16,12 +16,14 @@ #include "ThreadElfCore.h" #include "ProcessElfCore.h" +#include "Plugins/Process/Utility/RegisterContextLinux_arm.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" +#include "RegisterContextPOSIXCore_arm.h" #include "RegisterContextPOSIXCore_arm64.h" #include "RegisterContextPOSIXCore_mips64.h" #include "RegisterContextPOSIXCore_powerpc.h" @@ -127,6 +129,9 @@ { switch (arch.GetMachine()) { + case llvm::Triple::arm: + reg_interface = new RegisterContextLinux_arm(arch); + break; case llvm::Triple::x86_64: reg_interface = new RegisterContextLinux_x86_64(arch); break; @@ -152,6 +157,9 @@ case llvm::Triple::aarch64: m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); break; + case llvm::Triple::arm: + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm (*this, reg_interface, m_gpregset_data, m_fpregset_data)); + break; case llvm::Triple::mips64: m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); break;