11e209fccSTamas Berghammer //===-- NativeRegisterContextLinux_arm64.cpp --------------------*- C++ -*-===// 21e209fccSTamas Berghammer // 31e209fccSTamas Berghammer // The LLVM Compiler Infrastructure 41e209fccSTamas Berghammer // 51e209fccSTamas Berghammer // This file is distributed under the University of Illinois Open Source 61e209fccSTamas Berghammer // License. See LICENSE.TXT for details. 71e209fccSTamas Berghammer // 81e209fccSTamas Berghammer //===----------------------------------------------------------------------===// 91e209fccSTamas Berghammer 10068f8a7eSTamas Berghammer #if defined (__arm64__) || defined (__aarch64__) 11068f8a7eSTamas Berghammer 121e209fccSTamas Berghammer #include "NativeRegisterContextLinux_arm64.h" 131e209fccSTamas Berghammer 14068f8a7eSTamas Berghammer // C Includes 15068f8a7eSTamas Berghammer // C++ Includes 16068f8a7eSTamas Berghammer 17068f8a7eSTamas Berghammer // Other libraries and framework includes 181e209fccSTamas Berghammer #include "lldb/Core/DataBufferHeap.h" 191e209fccSTamas Berghammer #include "lldb/Core/Error.h" 20068f8a7eSTamas Berghammer #include "lldb/Core/Log.h" 211e209fccSTamas Berghammer #include "lldb/Core/RegisterValue.h" 221e209fccSTamas Berghammer #include "lldb/Host/common/NativeProcessProtocol.h" 231e209fccSTamas Berghammer 24068f8a7eSTamas Berghammer #include "Plugins/Process/Linux/NativeProcessLinux.h" 25068f8a7eSTamas Berghammer #include "Plugins/Process/Linux/Procfs.h" 26068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" 27068f8a7eSTamas Berghammer 28068f8a7eSTamas Berghammer // System includes - They have to be included after framework includes because they define some 29068f8a7eSTamas Berghammer // macros which collide with variable names in other modules 30068f8a7eSTamas Berghammer #include <sys/socket.h> 31068f8a7eSTamas Berghammer // NT_PRSTATUS and NT_FPREGSET definition 32068f8a7eSTamas Berghammer #include <elf.h> 33068f8a7eSTamas Berghammer 34068f8a7eSTamas Berghammer #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) 351e209fccSTamas Berghammer 361e209fccSTamas Berghammer using namespace lldb; 371e209fccSTamas Berghammer using namespace lldb_private; 38db264a6dSTamas Berghammer using namespace lldb_private::process_linux; 391e209fccSTamas Berghammer 401e209fccSTamas Berghammer // ARM64 general purpose registers. 411e209fccSTamas Berghammer static const uint32_t g_gpr_regnums_arm64[] = 421e209fccSTamas Berghammer { 431e209fccSTamas Berghammer gpr_x0_arm64, 441e209fccSTamas Berghammer gpr_x1_arm64, 451e209fccSTamas Berghammer gpr_x2_arm64, 461e209fccSTamas Berghammer gpr_x3_arm64, 471e209fccSTamas Berghammer gpr_x4_arm64, 481e209fccSTamas Berghammer gpr_x5_arm64, 491e209fccSTamas Berghammer gpr_x6_arm64, 501e209fccSTamas Berghammer gpr_x7_arm64, 511e209fccSTamas Berghammer gpr_x8_arm64, 521e209fccSTamas Berghammer gpr_x9_arm64, 531e209fccSTamas Berghammer gpr_x10_arm64, 541e209fccSTamas Berghammer gpr_x11_arm64, 551e209fccSTamas Berghammer gpr_x12_arm64, 561e209fccSTamas Berghammer gpr_x13_arm64, 571e209fccSTamas Berghammer gpr_x14_arm64, 581e209fccSTamas Berghammer gpr_x15_arm64, 591e209fccSTamas Berghammer gpr_x16_arm64, 601e209fccSTamas Berghammer gpr_x17_arm64, 611e209fccSTamas Berghammer gpr_x18_arm64, 621e209fccSTamas Berghammer gpr_x19_arm64, 631e209fccSTamas Berghammer gpr_x20_arm64, 641e209fccSTamas Berghammer gpr_x21_arm64, 651e209fccSTamas Berghammer gpr_x22_arm64, 661e209fccSTamas Berghammer gpr_x23_arm64, 671e209fccSTamas Berghammer gpr_x24_arm64, 681e209fccSTamas Berghammer gpr_x25_arm64, 691e209fccSTamas Berghammer gpr_x26_arm64, 701e209fccSTamas Berghammer gpr_x27_arm64, 711e209fccSTamas Berghammer gpr_x28_arm64, 721e209fccSTamas Berghammer gpr_fp_arm64, 731e209fccSTamas Berghammer gpr_lr_arm64, 741e209fccSTamas Berghammer gpr_sp_arm64, 751e209fccSTamas Berghammer gpr_pc_arm64, 761e209fccSTamas Berghammer gpr_cpsr_arm64, 771e209fccSTamas Berghammer LLDB_INVALID_REGNUM // register sets need to end with this flag 781e209fccSTamas Berghammer }; 791e209fccSTamas Berghammer static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \ 801e209fccSTamas Berghammer "g_gpr_regnums_arm64 has wrong number of register infos"); 811e209fccSTamas Berghammer 821e209fccSTamas Berghammer // ARM64 floating point registers. 831e209fccSTamas Berghammer static const uint32_t g_fpu_regnums_arm64[] = 841e209fccSTamas Berghammer { 851e209fccSTamas Berghammer fpu_v0_arm64, 861e209fccSTamas Berghammer fpu_v1_arm64, 871e209fccSTamas Berghammer fpu_v2_arm64, 881e209fccSTamas Berghammer fpu_v3_arm64, 891e209fccSTamas Berghammer fpu_v4_arm64, 901e209fccSTamas Berghammer fpu_v5_arm64, 911e209fccSTamas Berghammer fpu_v6_arm64, 921e209fccSTamas Berghammer fpu_v7_arm64, 931e209fccSTamas Berghammer fpu_v8_arm64, 941e209fccSTamas Berghammer fpu_v9_arm64, 951e209fccSTamas Berghammer fpu_v10_arm64, 961e209fccSTamas Berghammer fpu_v11_arm64, 971e209fccSTamas Berghammer fpu_v12_arm64, 981e209fccSTamas Berghammer fpu_v13_arm64, 991e209fccSTamas Berghammer fpu_v14_arm64, 1001e209fccSTamas Berghammer fpu_v15_arm64, 1011e209fccSTamas Berghammer fpu_v16_arm64, 1021e209fccSTamas Berghammer fpu_v17_arm64, 1031e209fccSTamas Berghammer fpu_v18_arm64, 1041e209fccSTamas Berghammer fpu_v19_arm64, 1051e209fccSTamas Berghammer fpu_v20_arm64, 1061e209fccSTamas Berghammer fpu_v21_arm64, 1071e209fccSTamas Berghammer fpu_v22_arm64, 1081e209fccSTamas Berghammer fpu_v23_arm64, 1091e209fccSTamas Berghammer fpu_v24_arm64, 1101e209fccSTamas Berghammer fpu_v25_arm64, 1111e209fccSTamas Berghammer fpu_v26_arm64, 1121e209fccSTamas Berghammer fpu_v27_arm64, 1131e209fccSTamas Berghammer fpu_v28_arm64, 1141e209fccSTamas Berghammer fpu_v29_arm64, 1151e209fccSTamas Berghammer fpu_v30_arm64, 1161e209fccSTamas Berghammer fpu_v31_arm64, 1171e209fccSTamas Berghammer fpu_fpsr_arm64, 1181e209fccSTamas Berghammer fpu_fpcr_arm64, 1191e209fccSTamas Berghammer LLDB_INVALID_REGNUM // register sets need to end with this flag 1201e209fccSTamas Berghammer }; 1211e209fccSTamas Berghammer static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \ 1221e209fccSTamas Berghammer "g_fpu_regnums_arm64 has wrong number of register infos"); 1231e209fccSTamas Berghammer 1241e209fccSTamas Berghammer namespace { 1251e209fccSTamas Berghammer // Number of register sets provided by this context. 1261e209fccSTamas Berghammer enum 1271e209fccSTamas Berghammer { 1281e209fccSTamas Berghammer k_num_register_sets = 2 1291e209fccSTamas Berghammer }; 1301e209fccSTamas Berghammer } 1311e209fccSTamas Berghammer 1321e209fccSTamas Berghammer // Register sets for ARM64. 133db264a6dSTamas Berghammer static const RegisterSet 1341e209fccSTamas Berghammer g_reg_sets_arm64[k_num_register_sets] = 1351e209fccSTamas Berghammer { 1361e209fccSTamas Berghammer { "General Purpose Registers", "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 }, 1371e209fccSTamas Berghammer { "Floating Point Registers", "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 } 1381e209fccSTamas Berghammer }; 1391e209fccSTamas Berghammer 140068f8a7eSTamas Berghammer NativeRegisterContextLinux* 141068f8a7eSTamas Berghammer NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch, 142068f8a7eSTamas Berghammer NativeThreadProtocol &native_thread, 143068f8a7eSTamas Berghammer uint32_t concrete_frame_idx) 144068f8a7eSTamas Berghammer { 145068f8a7eSTamas Berghammer return new NativeRegisterContextLinux_arm64(target_arch, native_thread, concrete_frame_idx); 146068f8a7eSTamas Berghammer } 147068f8a7eSTamas Berghammer 148068f8a7eSTamas Berghammer NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (const ArchSpec& target_arch, 149068f8a7eSTamas Berghammer NativeThreadProtocol &native_thread, 150068f8a7eSTamas Berghammer uint32_t concrete_frame_idx) : 151068f8a7eSTamas Berghammer NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm64(target_arch)) 152068f8a7eSTamas Berghammer { 153068f8a7eSTamas Berghammer switch (target_arch.GetMachine()) 1541e209fccSTamas Berghammer { 1551e209fccSTamas Berghammer case llvm::Triple::aarch64: 1561e209fccSTamas Berghammer m_reg_info.num_registers = k_num_registers_arm64; 1571e209fccSTamas Berghammer m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64; 1581e209fccSTamas Berghammer m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64; 1591e209fccSTamas Berghammer m_reg_info.last_gpr = k_last_gpr_arm64; 1601e209fccSTamas Berghammer m_reg_info.first_fpr = k_first_fpr_arm64; 1611e209fccSTamas Berghammer m_reg_info.last_fpr = k_last_fpr_arm64; 1621e209fccSTamas Berghammer m_reg_info.first_fpr_v = fpu_v0_arm64; 1631e209fccSTamas Berghammer m_reg_info.last_fpr_v = fpu_v31_arm64; 1641e209fccSTamas Berghammer m_reg_info.gpr_flags = gpr_cpsr_arm64; 1651e209fccSTamas Berghammer break; 1661e209fccSTamas Berghammer default: 1671e209fccSTamas Berghammer assert(false && "Unhandled target architecture."); 1681e209fccSTamas Berghammer break; 1691e209fccSTamas Berghammer } 1701e209fccSTamas Berghammer 1711e209fccSTamas Berghammer ::memset(&m_fpr, 0, sizeof (m_fpr)); 1721e209fccSTamas Berghammer ::memset(&m_gpr_arm64, 0, sizeof (m_gpr_arm64)); 173ea8c25a8SOmair Javaid ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs)); 174ea8c25a8SOmair Javaid 175ea8c25a8SOmair Javaid // 16 is just a maximum value, query hardware for actual watchpoint count 176ea8c25a8SOmair Javaid m_max_hwp_supported = 16; 177ea8c25a8SOmair Javaid m_max_hbp_supported = 16; 178ea8c25a8SOmair Javaid m_refresh_hwdebug_info = true; 1791e209fccSTamas Berghammer } 1801e209fccSTamas Berghammer 1811e209fccSTamas Berghammer uint32_t 1821e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetRegisterSetCount () const 1831e209fccSTamas Berghammer { 1841e209fccSTamas Berghammer return k_num_register_sets; 1851e209fccSTamas Berghammer } 1861e209fccSTamas Berghammer 187db264a6dSTamas Berghammer const RegisterSet * 1881e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetRegisterSet (uint32_t set_index) const 1891e209fccSTamas Berghammer { 1901e209fccSTamas Berghammer if (set_index < k_num_register_sets) 1911e209fccSTamas Berghammer return &g_reg_sets_arm64[set_index]; 1921e209fccSTamas Berghammer 1931e209fccSTamas Berghammer return nullptr; 1941e209fccSTamas Berghammer } 1951e209fccSTamas Berghammer 196db264a6dSTamas Berghammer Error 1971e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) 1981e209fccSTamas Berghammer { 1991e209fccSTamas Berghammer Error error; 2001e209fccSTamas Berghammer 2011e209fccSTamas Berghammer if (!reg_info) 2021e209fccSTamas Berghammer { 2031e209fccSTamas Berghammer error.SetErrorString ("reg_info NULL"); 2041e209fccSTamas Berghammer return error; 2051e209fccSTamas Berghammer } 2061e209fccSTamas Berghammer 2071e209fccSTamas Berghammer const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 2081e209fccSTamas Berghammer 2091e209fccSTamas Berghammer if (IsFPR(reg)) 2101e209fccSTamas Berghammer { 211068f8a7eSTamas Berghammer error = ReadFPR(); 212068f8a7eSTamas Berghammer if (error.Fail()) 2131e209fccSTamas Berghammer return error; 2141e209fccSTamas Berghammer } 2151e209fccSTamas Berghammer else 2161e209fccSTamas Berghammer { 2171e209fccSTamas Berghammer uint32_t full_reg = reg; 2181e209fccSTamas Berghammer bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 2191e209fccSTamas Berghammer 2201e209fccSTamas Berghammer if (is_subreg) 2211e209fccSTamas Berghammer { 2221e209fccSTamas Berghammer // Read the full aligned 64-bit register. 2231e209fccSTamas Berghammer full_reg = reg_info->invalidate_regs[0]; 2241e209fccSTamas Berghammer } 2251e209fccSTamas Berghammer 2261e209fccSTamas Berghammer error = ReadRegisterRaw(full_reg, reg_value); 2271e209fccSTamas Berghammer 2281e209fccSTamas Berghammer if (error.Success ()) 2291e209fccSTamas Berghammer { 2301e209fccSTamas Berghammer // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. 2311e209fccSTamas Berghammer if (is_subreg && (reg_info->byte_offset & 0x1)) 2321e209fccSTamas Berghammer reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); 2331e209fccSTamas Berghammer 2341e209fccSTamas Berghammer // If our return byte size was greater than the return value reg size, then 2351e209fccSTamas Berghammer // use the type specified by reg_info rather than the uint64_t default 2361e209fccSTamas Berghammer if (reg_value.GetByteSize() > reg_info->byte_size) 2371e209fccSTamas Berghammer reg_value.SetType(reg_info); 2381e209fccSTamas Berghammer } 2391e209fccSTamas Berghammer return error; 2401e209fccSTamas Berghammer } 2411e209fccSTamas Berghammer 2421e209fccSTamas Berghammer // Get pointer to m_fpr variable and set the data from it. 2431e209fccSTamas Berghammer assert (reg_info->byte_offset < sizeof m_fpr); 2441e209fccSTamas Berghammer uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; 2451e209fccSTamas Berghammer switch (reg_info->byte_size) 2461e209fccSTamas Berghammer { 2471e209fccSTamas Berghammer case 2: 2481e209fccSTamas Berghammer reg_value.SetUInt16(*(uint16_t *)src); 2491e209fccSTamas Berghammer break; 2501e209fccSTamas Berghammer case 4: 2511e209fccSTamas Berghammer reg_value.SetUInt32(*(uint32_t *)src); 2521e209fccSTamas Berghammer break; 2531e209fccSTamas Berghammer case 8: 2541e209fccSTamas Berghammer reg_value.SetUInt64(*(uint64_t *)src); 2551e209fccSTamas Berghammer break; 2561e209fccSTamas Berghammer default: 2571e209fccSTamas Berghammer assert(false && "Unhandled data size."); 2581e209fccSTamas Berghammer error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size); 2591e209fccSTamas Berghammer break; 2601e209fccSTamas Berghammer } 2611e209fccSTamas Berghammer 2621e209fccSTamas Berghammer return error; 2631e209fccSTamas Berghammer } 2641e209fccSTamas Berghammer 265db264a6dSTamas Berghammer Error 2661e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) 2671e209fccSTamas Berghammer { 2681e209fccSTamas Berghammer if (!reg_info) 2691e209fccSTamas Berghammer return Error ("reg_info NULL"); 2701e209fccSTamas Berghammer 2711e209fccSTamas Berghammer const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 2721e209fccSTamas Berghammer if (reg_index == LLDB_INVALID_REGNUM) 2731e209fccSTamas Berghammer return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>"); 2741e209fccSTamas Berghammer 2751e209fccSTamas Berghammer if (IsGPR(reg_index)) 2761e209fccSTamas Berghammer return WriteRegisterRaw(reg_index, reg_value); 2771e209fccSTamas Berghammer 2781e209fccSTamas Berghammer if (IsFPR(reg_index)) 2791e209fccSTamas Berghammer { 2801e209fccSTamas Berghammer // Get pointer to m_fpr variable and set the data to it. 2811e209fccSTamas Berghammer assert (reg_info->byte_offset < sizeof(m_fpr)); 2821e209fccSTamas Berghammer uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset; 2831e209fccSTamas Berghammer switch (reg_info->byte_size) 2841e209fccSTamas Berghammer { 2851e209fccSTamas Berghammer case 2: 2861e209fccSTamas Berghammer *(uint16_t *)dst = reg_value.GetAsUInt16(); 2871e209fccSTamas Berghammer break; 2881e209fccSTamas Berghammer case 4: 2891e209fccSTamas Berghammer *(uint32_t *)dst = reg_value.GetAsUInt32(); 2901e209fccSTamas Berghammer break; 2911e209fccSTamas Berghammer case 8: 2921e209fccSTamas Berghammer *(uint64_t *)dst = reg_value.GetAsUInt64(); 2931e209fccSTamas Berghammer break; 2941e209fccSTamas Berghammer default: 2951e209fccSTamas Berghammer assert(false && "Unhandled data size."); 2961e209fccSTamas Berghammer return Error ("unhandled register data size %" PRIu32, reg_info->byte_size); 2971e209fccSTamas Berghammer } 2981e209fccSTamas Berghammer 299068f8a7eSTamas Berghammer Error error = WriteFPR(); 300068f8a7eSTamas Berghammer if (error.Fail()) 301068f8a7eSTamas Berghammer return error; 3021e209fccSTamas Berghammer 3031e209fccSTamas Berghammer return Error (); 3041e209fccSTamas Berghammer } 3051e209fccSTamas Berghammer 3061e209fccSTamas Berghammer return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown"); 3071e209fccSTamas Berghammer } 3081e209fccSTamas Berghammer 309db264a6dSTamas Berghammer Error 3101e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) 3111e209fccSTamas Berghammer { 3121e209fccSTamas Berghammer Error error; 3131e209fccSTamas Berghammer 314db264a6dSTamas Berghammer data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); 3151e209fccSTamas Berghammer if (!data_sp) 3161e209fccSTamas Berghammer return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE); 3171e209fccSTamas Berghammer 318068f8a7eSTamas Berghammer error = ReadGPR(); 319068f8a7eSTamas Berghammer if (error.Fail()) 3201e209fccSTamas Berghammer return error; 3211e209fccSTamas Berghammer 322068f8a7eSTamas Berghammer error = ReadFPR(); 323068f8a7eSTamas Berghammer if (error.Fail()) 3241e209fccSTamas Berghammer return error; 3251e209fccSTamas Berghammer 3261e209fccSTamas Berghammer uint8_t *dst = data_sp->GetBytes (); 3271e209fccSTamas Berghammer if (dst == nullptr) 3281e209fccSTamas Berghammer { 3291e209fccSTamas Berghammer error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE); 3301e209fccSTamas Berghammer return error; 3311e209fccSTamas Berghammer } 3321e209fccSTamas Berghammer 3331e209fccSTamas Berghammer ::memcpy (dst, &m_gpr_arm64, GetGPRSize()); 3341e209fccSTamas Berghammer dst += GetGPRSize(); 3351e209fccSTamas Berghammer ::memcpy (dst, &m_fpr, sizeof(m_fpr)); 3361e209fccSTamas Berghammer 3371e209fccSTamas Berghammer return error; 3381e209fccSTamas Berghammer } 3391e209fccSTamas Berghammer 340db264a6dSTamas Berghammer Error 3411e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) 3421e209fccSTamas Berghammer { 3431e209fccSTamas Berghammer Error error; 3441e209fccSTamas Berghammer 3451e209fccSTamas Berghammer if (!data_sp) 3461e209fccSTamas Berghammer { 3471e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__); 3481e209fccSTamas Berghammer return error; 3491e209fccSTamas Berghammer } 3501e209fccSTamas Berghammer 3511e209fccSTamas Berghammer if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) 3521e209fccSTamas Berghammer { 3531e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ()); 3541e209fccSTamas Berghammer return error; 3551e209fccSTamas Berghammer } 3561e209fccSTamas Berghammer 3571e209fccSTamas Berghammer 3581e209fccSTamas Berghammer uint8_t *src = data_sp->GetBytes (); 3591e209fccSTamas Berghammer if (src == nullptr) 3601e209fccSTamas Berghammer { 3611e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); 3621e209fccSTamas Berghammer return error; 3631e209fccSTamas Berghammer } 3641e209fccSTamas Berghammer ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ()); 3651e209fccSTamas Berghammer 366068f8a7eSTamas Berghammer error = WriteGPR(); 367068f8a7eSTamas Berghammer if (error.Fail()) 3681e209fccSTamas Berghammer return error; 3691e209fccSTamas Berghammer 3701e209fccSTamas Berghammer src += GetRegisterInfoInterface ().GetGPRSize (); 3711e209fccSTamas Berghammer ::memcpy (&m_fpr, src, sizeof(m_fpr)); 3721e209fccSTamas Berghammer 373068f8a7eSTamas Berghammer error = WriteFPR(); 3741e209fccSTamas Berghammer if (error.Fail()) 3751e209fccSTamas Berghammer return error; 3761e209fccSTamas Berghammer 3771e209fccSTamas Berghammer return error; 3781e209fccSTamas Berghammer } 3791e209fccSTamas Berghammer 3801e209fccSTamas Berghammer bool 3811e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const 3821e209fccSTamas Berghammer { 3831e209fccSTamas Berghammer return reg <= m_reg_info.last_gpr; // GPR's come first. 3841e209fccSTamas Berghammer } 3851e209fccSTamas Berghammer 3861e209fccSTamas Berghammer bool 3871e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const 3881e209fccSTamas Berghammer { 3891e209fccSTamas Berghammer return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 3901e209fccSTamas Berghammer } 3911e209fccSTamas Berghammer 392ea8c25a8SOmair Javaid uint32_t 393ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) 394ea8c25a8SOmair Javaid { 395ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 396ea8c25a8SOmair Javaid 397ea8c25a8SOmair Javaid if (log) 398ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 399ea8c25a8SOmair Javaid 400ea8c25a8SOmair Javaid NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 401ea8c25a8SOmair Javaid if (!process_sp) 402ea8c25a8SOmair Javaid return false; 403ea8c25a8SOmair Javaid 404ea8c25a8SOmair Javaid // Check if our hardware breakpoint and watchpoint information is updated. 405ea8c25a8SOmair Javaid if (m_refresh_hwdebug_info) 406ea8c25a8SOmair Javaid { 407068f8a7eSTamas Berghammer ReadHardwareDebugInfo (m_max_hwp_supported, m_max_hbp_supported); 408ea8c25a8SOmair Javaid m_refresh_hwdebug_info = false; 409ea8c25a8SOmair Javaid } 410ea8c25a8SOmair Javaid 411ea8c25a8SOmair Javaid uint32_t control_value, bp_index; 412ea8c25a8SOmair Javaid 413ea8c25a8SOmair Javaid // Check if size has a valid hardware breakpoint length. 414ea8c25a8SOmair Javaid if (size != 4) 415ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware breakpoint 416ea8c25a8SOmair Javaid 417ea8c25a8SOmair Javaid // Check 4-byte alignment for hardware breakpoint target address. 418ea8c25a8SOmair Javaid if (addr & 0x03) 419ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. 420ea8c25a8SOmair Javaid 421ea8c25a8SOmair Javaid // Setup control value 422ea8c25a8SOmair Javaid control_value = 0; 423ea8c25a8SOmair Javaid control_value |= ((1 << size) - 1) << 5; 424ea8c25a8SOmair Javaid control_value |= (2 << 1) | 1; 425ea8c25a8SOmair Javaid 426ea8c25a8SOmair Javaid // Iterate over stored hardware breakpoints 427ea8c25a8SOmair Javaid // Find a free bp_index or update reference count if duplicate. 428ea8c25a8SOmair Javaid bp_index = LLDB_INVALID_INDEX32; 429ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hbp_supported; i++) 430ea8c25a8SOmair Javaid { 431ea8c25a8SOmair Javaid if ((m_hbr_regs[i].control & 1) == 0) 432ea8c25a8SOmair Javaid { 433ea8c25a8SOmair Javaid bp_index = i; // Mark last free slot 434ea8c25a8SOmair Javaid } 435ea8c25a8SOmair Javaid else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value) 436ea8c25a8SOmair Javaid { 437ea8c25a8SOmair Javaid bp_index = i; // Mark duplicate index 438ea8c25a8SOmair Javaid break; // Stop searching here 439ea8c25a8SOmair Javaid } 440ea8c25a8SOmair Javaid } 441ea8c25a8SOmair Javaid 442ea8c25a8SOmair Javaid if (bp_index == LLDB_INVALID_INDEX32) 443ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; 444ea8c25a8SOmair Javaid 445ea8c25a8SOmair Javaid // Add new or update existing watchpoint 446ea8c25a8SOmair Javaid if ((m_hbr_regs[bp_index].control & 1) == 0) 447ea8c25a8SOmair Javaid { 448ea8c25a8SOmair Javaid m_hbr_regs[bp_index].address = addr; 449ea8c25a8SOmair Javaid m_hbr_regs[bp_index].control = control_value; 450ea8c25a8SOmair Javaid m_hbr_regs[bp_index].refcount = 1; 451ea8c25a8SOmair Javaid 452ea8c25a8SOmair Javaid //TODO: PTRACE CALL HERE for an UPDATE 453ea8c25a8SOmair Javaid } 454ea8c25a8SOmair Javaid else 455ea8c25a8SOmair Javaid m_hbr_regs[bp_index].refcount++; 456ea8c25a8SOmair Javaid 457ea8c25a8SOmair Javaid return bp_index; 458ea8c25a8SOmair Javaid } 459ea8c25a8SOmair Javaid 460ea8c25a8SOmair Javaid bool 461ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx) 462ea8c25a8SOmair Javaid { 463ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 464ea8c25a8SOmair Javaid 465ea8c25a8SOmair Javaid if (log) 466ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 467ea8c25a8SOmair Javaid 468ea8c25a8SOmair Javaid if (hw_idx >= m_max_hbp_supported) 469ea8c25a8SOmair Javaid return false; 470ea8c25a8SOmair Javaid 471ea8c25a8SOmair Javaid // Update reference count if multiple references. 472ea8c25a8SOmair Javaid if (m_hbr_regs[hw_idx].refcount > 1) 473ea8c25a8SOmair Javaid { 474ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].refcount--; 475ea8c25a8SOmair Javaid return true; 476ea8c25a8SOmair Javaid } 477ea8c25a8SOmair Javaid else if (m_hbr_regs[hw_idx].refcount == 1) 478ea8c25a8SOmair Javaid { 479ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].control &= ~1; 480ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].address = 0; 481ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].refcount = 0; 482ea8c25a8SOmair Javaid 483ea8c25a8SOmair Javaid //TODO: PTRACE CALL HERE for an UPDATE 484ea8c25a8SOmair Javaid return true; 485ea8c25a8SOmair Javaid } 486ea8c25a8SOmair Javaid 487ea8c25a8SOmair Javaid return false; 488ea8c25a8SOmair Javaid } 489ea8c25a8SOmair Javaid 490ea8c25a8SOmair Javaid uint32_t 491ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints () 492ea8c25a8SOmair Javaid { 493ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 494ea8c25a8SOmair Javaid 495ea8c25a8SOmair Javaid if (log) 496ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 497ea8c25a8SOmair Javaid 498ea8c25a8SOmair Javaid return m_max_hwp_supported; 499ea8c25a8SOmair Javaid } 500ea8c25a8SOmair Javaid 501ea8c25a8SOmair Javaid uint32_t 502ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) 503ea8c25a8SOmair Javaid { 504ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 505ea8c25a8SOmair Javaid 506ea8c25a8SOmair Javaid if (log) 507ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 508ea8c25a8SOmair Javaid 509ea8c25a8SOmair Javaid NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 510ea8c25a8SOmair Javaid if (!process_sp) 511ea8c25a8SOmair Javaid return false; 512ea8c25a8SOmair Javaid 513068f8a7eSTamas Berghammer 514ea8c25a8SOmair Javaid // Check if our hardware breakpoint and watchpoint information is updated. 515ea8c25a8SOmair Javaid if (m_refresh_hwdebug_info) 516ea8c25a8SOmair Javaid { 517068f8a7eSTamas Berghammer ReadHardwareDebugInfo (m_max_hwp_supported, m_max_hbp_supported); 518ea8c25a8SOmair Javaid m_refresh_hwdebug_info = false; 519ea8c25a8SOmair Javaid } 520ea8c25a8SOmair Javaid 521ea8c25a8SOmair Javaid uint32_t control_value, wp_index; 522ea8c25a8SOmair Javaid 523ea8c25a8SOmair Javaid 524ea8c25a8SOmair Javaid if (watch_flags != 0x1 && watch_flags != 0x2 && watch_flags != 0x3) 525ea8c25a8SOmair Javaid return 0;//Error ("Invalid read/write bits for watchpoint"); 526ea8c25a8SOmair Javaid 527ea8c25a8SOmair Javaid // Check if size has a valid hardware watchpoint length. 528ea8c25a8SOmair Javaid if (size != 1 && size != 2 && size != 4 && size != 8) 529ea8c25a8SOmair Javaid return 0;//Error ("Invalid size for watchpoint"); 530ea8c25a8SOmair Javaid 531ea8c25a8SOmair Javaid // Check 8-byte alignment for hardware watchpoint target address. 532ea8c25a8SOmair Javaid // TODO: Add support for watching un-aligned addresses 533ea8c25a8SOmair Javaid if (addr & 0x07) 534ea8c25a8SOmair Javaid return 0;//Error ("LLDB for AArch64 currently supports 8-byte alignment for hardware watchpoint target address."); 535ea8c25a8SOmair Javaid 536ea8c25a8SOmair Javaid // Setup control value 537ea8c25a8SOmair Javaid control_value = watch_flags << 3; 538ea8c25a8SOmair Javaid control_value |= ((1 << size) - 1) << 5; 539ea8c25a8SOmair Javaid control_value |= (2 << 1) | 1; 540ea8c25a8SOmair Javaid 541ea8c25a8SOmair Javaid // Iterate over stored watchpoints 542ea8c25a8SOmair Javaid // Find a free wp_index or update reference count if duplicate. 543ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 544ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 545ea8c25a8SOmair Javaid { 546ea8c25a8SOmair Javaid if ((m_hwp_regs[i].control & 1) == 0) 547ea8c25a8SOmair Javaid { 548ea8c25a8SOmair Javaid wp_index = i; // Mark last free slot 549ea8c25a8SOmair Javaid } 550ea8c25a8SOmair Javaid else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value) 551ea8c25a8SOmair Javaid { 552ea8c25a8SOmair Javaid wp_index = i; // Mark duplicate index 553ea8c25a8SOmair Javaid break; // Stop searching here 554ea8c25a8SOmair Javaid } 555ea8c25a8SOmair Javaid } 556ea8c25a8SOmair Javaid 557ea8c25a8SOmair Javaid if (wp_index == LLDB_INVALID_INDEX32) 558ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; 559ea8c25a8SOmair Javaid 560ea8c25a8SOmair Javaid // Add new or update existing watchpoint 561ea8c25a8SOmair Javaid if ((m_hwp_regs[wp_index].control & 1) == 0) 562ea8c25a8SOmair Javaid { 563ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = addr; 564ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control = control_value; 565ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount = 1; 566ea8c25a8SOmair Javaid 567ea8c25a8SOmair Javaid // PTRACE call to set corresponding watchpoint register. 568068f8a7eSTamas Berghammer WriteHardwareDebugRegs(&addr, &control_value, 0, wp_index); 569ea8c25a8SOmair Javaid } 570ea8c25a8SOmair Javaid else 571ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount++; 572ea8c25a8SOmair Javaid 573ea8c25a8SOmair Javaid return wp_index; 574ea8c25a8SOmair Javaid } 575ea8c25a8SOmair Javaid 576ea8c25a8SOmair Javaid bool 577ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index) 578ea8c25a8SOmair Javaid { 579ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 580ea8c25a8SOmair Javaid 581ea8c25a8SOmair Javaid if (log) 582ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 583ea8c25a8SOmair Javaid 584ea8c25a8SOmair Javaid NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 585ea8c25a8SOmair Javaid if (!process_sp) 586ea8c25a8SOmair Javaid return false; 587ea8c25a8SOmair Javaid 588ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 589ea8c25a8SOmair Javaid return false; 590ea8c25a8SOmair Javaid 591ea8c25a8SOmair Javaid // Update reference count if multiple references. 592ea8c25a8SOmair Javaid if (m_hwp_regs[wp_index].refcount > 1) 593ea8c25a8SOmair Javaid { 594ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount--; 595ea8c25a8SOmair Javaid return true; 596ea8c25a8SOmair Javaid } 597ea8c25a8SOmair Javaid else if (m_hwp_regs[wp_index].refcount == 1) 598ea8c25a8SOmair Javaid { 599ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control &= ~1; 600ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = 0; 601ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount = 0; 602ea8c25a8SOmair Javaid 603ea8c25a8SOmair Javaid //TODO: PTRACE CALL HERE for an UPDATE 604068f8a7eSTamas Berghammer WriteHardwareDebugRegs(&m_hwp_regs[wp_index].address, &m_hwp_regs[wp_index].control, 0, wp_index); 605ea8c25a8SOmair Javaid return true; 606ea8c25a8SOmair Javaid } 607ea8c25a8SOmair Javaid 608ea8c25a8SOmair Javaid return false; 609ea8c25a8SOmair Javaid } 610ea8c25a8SOmair Javaid 611ea8c25a8SOmair Javaid Error 612ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints () 613ea8c25a8SOmair Javaid { 614ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 615ea8c25a8SOmair Javaid 616ea8c25a8SOmair Javaid if (log) 617ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 618ea8c25a8SOmair Javaid 619ea8c25a8SOmair Javaid NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 620ea8c25a8SOmair Javaid 621ea8c25a8SOmair Javaid Error ml_error; 622ea8c25a8SOmair Javaid ml_error.SetErrorToErrno(); 623ea8c25a8SOmair Javaid if (!process_sp) 624ea8c25a8SOmair Javaid return ml_error; 625ea8c25a8SOmair Javaid 626ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 627ea8c25a8SOmair Javaid { 628ea8c25a8SOmair Javaid if (m_hwp_regs[i].control & 0x01) 629ea8c25a8SOmair Javaid { 630ea8c25a8SOmair Javaid m_hwp_regs[i].control &= ~1; 631ea8c25a8SOmair Javaid m_hwp_regs[i].address = 0; 632ea8c25a8SOmair Javaid m_hwp_regs[i].refcount = 0; 633ea8c25a8SOmair Javaid 634068f8a7eSTamas Berghammer WriteHardwareDebugRegs(&m_hwp_regs[i].address, &m_hwp_regs[i].control, 0, i); 635ea8c25a8SOmair Javaid } 636ea8c25a8SOmair Javaid } 637ea8c25a8SOmair Javaid 638ea8c25a8SOmair Javaid return Error(); 639ea8c25a8SOmair Javaid } 640ea8c25a8SOmair Javaid 641ea8c25a8SOmair Javaid uint32_t 642ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) 643ea8c25a8SOmair Javaid { 644ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 645ea8c25a8SOmair Javaid 646ea8c25a8SOmair Javaid if (log) 647ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 648ea8c25a8SOmair Javaid switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) 649ea8c25a8SOmair Javaid { 650ea8c25a8SOmair Javaid case 0x01: 651ea8c25a8SOmair Javaid return 1; 652ea8c25a8SOmair Javaid case 0x03: 653ea8c25a8SOmair Javaid return 2; 654ea8c25a8SOmair Javaid case 0x0f: 655ea8c25a8SOmair Javaid return 4; 656ea8c25a8SOmair Javaid case 0xff: 657ea8c25a8SOmair Javaid return 8; 658ea8c25a8SOmair Javaid default: 659ea8c25a8SOmair Javaid return 0; 660ea8c25a8SOmair Javaid } 661ea8c25a8SOmair Javaid } 662ea8c25a8SOmair Javaid bool 663ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) 664ea8c25a8SOmair Javaid { 665ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 666ea8c25a8SOmair Javaid 667ea8c25a8SOmair Javaid if (log) 668ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 669ea8c25a8SOmair Javaid 670ea8c25a8SOmair Javaid if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 671ea8c25a8SOmair Javaid return true; 672ea8c25a8SOmair Javaid else 673ea8c25a8SOmair Javaid return false; 674ea8c25a8SOmair Javaid } 675ea8c25a8SOmair Javaid 676ea8c25a8SOmair Javaid Error 677ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) 678ea8c25a8SOmair Javaid { 679ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 680ea8c25a8SOmair Javaid 681ea8c25a8SOmair Javaid if (log) 682ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 683ea8c25a8SOmair Javaid 684ea8c25a8SOmair Javaid uint32_t watch_size; 685ea8c25a8SOmair Javaid lldb::addr_t watch_addr; 686ea8c25a8SOmair Javaid 687ea8c25a8SOmair Javaid for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) 688ea8c25a8SOmair Javaid { 689ea8c25a8SOmair Javaid watch_size = GetWatchpointSize (wp_index); 690ea8c25a8SOmair Javaid watch_addr = m_hwp_regs[wp_index].address; 691ea8c25a8SOmair Javaid 692ea8c25a8SOmair Javaid if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) 693ea8c25a8SOmair Javaid && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) 694ea8c25a8SOmair Javaid { 695ea8c25a8SOmair Javaid return Error(); 696ea8c25a8SOmair Javaid } 697ea8c25a8SOmair Javaid } 698ea8c25a8SOmair Javaid 699ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 700ea8c25a8SOmair Javaid return Error(); 701ea8c25a8SOmair Javaid } 702ea8c25a8SOmair Javaid 703ea8c25a8SOmair Javaid lldb::addr_t 704ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index) 705ea8c25a8SOmair Javaid { 706ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 707ea8c25a8SOmair Javaid 708ea8c25a8SOmair Javaid if (log) 709ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 710ea8c25a8SOmair Javaid 711ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 712ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 713ea8c25a8SOmair Javaid 714ea8c25a8SOmair Javaid if (WatchpointIsEnabled(wp_index)) 715ea8c25a8SOmair Javaid return m_hwp_regs[wp_index].address; 716ea8c25a8SOmair Javaid else 717ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 718ea8c25a8SOmair Javaid } 719ea8c25a8SOmair Javaid 720068f8a7eSTamas Berghammer Error 721068f8a7eSTamas Berghammer NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo(unsigned int &watch_count, 722068f8a7eSTamas Berghammer unsigned int &break_count) 723ea8c25a8SOmair Javaid { 724068f8a7eSTamas Berghammer NativeProcessProtocolSP process_sp (m_thread.GetProcess()); 725068f8a7eSTamas Berghammer if (!process_sp) 726068f8a7eSTamas Berghammer return Error("NativeProcessProtocol is NULL"); 727068f8a7eSTamas Berghammer NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*>(process_sp.get()); 728c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 729ea8c25a8SOmair Javaid 730c7512fdcSPavel Labath return process_p->DoOperation([&] { 731c7512fdcSPavel Labath int regset = NT_ARM_HW_WATCH; 732c7512fdcSPavel Labath struct iovec ioVec; 733c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 734c7512fdcSPavel Labath Error error; 735c7512fdcSPavel Labath 736c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 737c7512fdcSPavel Labath ioVec.iov_len = sizeof (dreg_state); 738*4a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 739c7512fdcSPavel Labath watch_count = dreg_state.dbg_info & 0xff; 740c7512fdcSPavel Labath 741c7512fdcSPavel Labath regset = NT_ARM_HW_BREAK; 742*4a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 743c7512fdcSPavel Labath break_count = dreg_state.dbg_info & 0xff; 744c7512fdcSPavel Labath 745c7512fdcSPavel Labath return error; 746c7512fdcSPavel Labath }); 747ea8c25a8SOmair Javaid } 748068f8a7eSTamas Berghammer 749068f8a7eSTamas Berghammer Error 750068f8a7eSTamas Berghammer NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(lldb::addr_t *addr_buf, 751068f8a7eSTamas Berghammer uint32_t *cntrl_buf, 752068f8a7eSTamas Berghammer int type, 753068f8a7eSTamas Berghammer int count) 754068f8a7eSTamas Berghammer { 755068f8a7eSTamas Berghammer NativeProcessProtocolSP process_sp (m_thread.GetProcess()); 756068f8a7eSTamas Berghammer if (!process_sp) 757068f8a7eSTamas Berghammer return Error("NativeProcessProtocol is NULL"); 758068f8a7eSTamas Berghammer NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*>(process_sp.get()); 759068f8a7eSTamas Berghammer 760c7512fdcSPavel Labath return process_p->DoOperation([&] { 761c7512fdcSPavel Labath struct iovec ioVec; 762c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 763c7512fdcSPavel Labath Error error; 764c7512fdcSPavel Labath 765c7512fdcSPavel Labath memset (&dreg_state, 0, sizeof (dreg_state)); 766c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 767c7512fdcSPavel Labath ioVec.iov_len = sizeof (dreg_state); 768c7512fdcSPavel Labath 769c7512fdcSPavel Labath if (type == 0) 770c7512fdcSPavel Labath type = NT_ARM_HW_WATCH; 771c7512fdcSPavel Labath else 772c7512fdcSPavel Labath type = NT_ARM_HW_BREAK; 773c7512fdcSPavel Labath 774c7512fdcSPavel Labath for (int i = 0; i < count; i++) 775c7512fdcSPavel Labath { 776c7512fdcSPavel Labath dreg_state.dbg_regs[i].addr = addr_buf[i]; 777c7512fdcSPavel Labath dreg_state.dbg_regs[i].ctrl = cntrl_buf[i]; 778068f8a7eSTamas Berghammer } 779068f8a7eSTamas Berghammer 780*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &type, &ioVec, ioVec.iov_len); 781c7512fdcSPavel Labath }); 782c7512fdcSPavel Labath } 783c7512fdcSPavel Labath 784c7512fdcSPavel Labath Error 785c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset, 786068f8a7eSTamas Berghammer const char* reg_name, 787068f8a7eSTamas Berghammer uint32_t size, 788068f8a7eSTamas Berghammer RegisterValue &value) 789068f8a7eSTamas Berghammer { 790c7512fdcSPavel Labath Error error; 791c7512fdcSPavel Labath if (offset > sizeof(struct user_pt_regs)) 792c7512fdcSPavel Labath { 793c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 794c7512fdcSPavel Labath if (offset > sizeof(struct user_fpsimd_state)) 795c7512fdcSPavel Labath { 796c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 797c7512fdcSPavel Labath return error; 798c7512fdcSPavel Labath } 799c7512fdcSPavel Labath elf_fpregset_t regs; 800c7512fdcSPavel Labath int regset = NT_FPREGSET; 801c7512fdcSPavel Labath struct iovec ioVec; 802c7512fdcSPavel Labath 803c7512fdcSPavel Labath ioVec.iov_base = ®s; 804c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 805*4a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 806*4a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 807c7512fdcSPavel Labath if (error.Success()) 808c7512fdcSPavel Labath { 809c7512fdcSPavel Labath ArchSpec arch; 810c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 811c7512fdcSPavel Labath value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, arch.GetByteOrder()); 812c7512fdcSPavel Labath else 813c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 814c7512fdcSPavel Labath } 815c7512fdcSPavel Labath } 816c7512fdcSPavel Labath else 817c7512fdcSPavel Labath { 818c7512fdcSPavel Labath elf_gregset_t regs; 819c7512fdcSPavel Labath int regset = NT_PRSTATUS; 820c7512fdcSPavel Labath struct iovec ioVec; 821c7512fdcSPavel Labath 822c7512fdcSPavel Labath ioVec.iov_base = ®s; 823c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 824*4a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 825*4a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 826c7512fdcSPavel Labath if (error.Success()) 827c7512fdcSPavel Labath { 828c7512fdcSPavel Labath ArchSpec arch; 829c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 830c7512fdcSPavel Labath value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder()); 831c7512fdcSPavel Labath else 832c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 833c7512fdcSPavel Labath } 834c7512fdcSPavel Labath } 835c7512fdcSPavel Labath return error; 836068f8a7eSTamas Berghammer } 837068f8a7eSTamas Berghammer 838c7512fdcSPavel Labath Error 839c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset, 840068f8a7eSTamas Berghammer const char* reg_name, 841068f8a7eSTamas Berghammer const RegisterValue &value) 842068f8a7eSTamas Berghammer { 843c7512fdcSPavel Labath Error error; 844c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 845c7512fdcSPavel Labath if (offset > sizeof(struct user_pt_regs)) 846c7512fdcSPavel Labath { 847c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 848c7512fdcSPavel Labath if (offset > sizeof(struct user_fpsimd_state)) 849c7512fdcSPavel Labath { 850c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 851c7512fdcSPavel Labath return error; 852c7512fdcSPavel Labath } 853c7512fdcSPavel Labath elf_fpregset_t regs; 854c7512fdcSPavel Labath int regset = NT_FPREGSET; 855c7512fdcSPavel Labath struct iovec ioVec; 856c7512fdcSPavel Labath 857c7512fdcSPavel Labath ioVec.iov_base = ®s; 858c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 859*4a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 860c7512fdcSPavel Labath 861c7512fdcSPavel Labath if (error.Success()) 862c7512fdcSPavel Labath { 863c7512fdcSPavel Labath ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 16); 864*4a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 865c7512fdcSPavel Labath } 866c7512fdcSPavel Labath } 867c7512fdcSPavel Labath else 868c7512fdcSPavel Labath { 869c7512fdcSPavel Labath elf_gregset_t regs; 870c7512fdcSPavel Labath int regset = NT_PRSTATUS; 871c7512fdcSPavel Labath struct iovec ioVec; 872c7512fdcSPavel Labath 873c7512fdcSPavel Labath ioVec.iov_base = ®s; 874c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 875*4a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 876c7512fdcSPavel Labath if (error.Success()) 877c7512fdcSPavel Labath { 878c7512fdcSPavel Labath ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 8); 879*4a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 880c7512fdcSPavel Labath } 881c7512fdcSPavel Labath } 882c7512fdcSPavel Labath return error; 883068f8a7eSTamas Berghammer } 884068f8a7eSTamas Berghammer 885c7512fdcSPavel Labath Error 886c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) 887068f8a7eSTamas Berghammer { 888c7512fdcSPavel Labath int regset = NT_PRSTATUS; 889c7512fdcSPavel Labath struct iovec ioVec; 890c7512fdcSPavel Labath Error error; 891c7512fdcSPavel Labath 892c7512fdcSPavel Labath ioVec.iov_base = buf; 893c7512fdcSPavel Labath ioVec.iov_len = buf_size; 894*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 895068f8a7eSTamas Berghammer } 896068f8a7eSTamas Berghammer 897c7512fdcSPavel Labath Error 898c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) 899068f8a7eSTamas Berghammer { 900c7512fdcSPavel Labath int regset = NT_PRSTATUS; 901c7512fdcSPavel Labath struct iovec ioVec; 902c7512fdcSPavel Labath Error error; 903c7512fdcSPavel Labath 904c7512fdcSPavel Labath ioVec.iov_base = buf; 905c7512fdcSPavel Labath ioVec.iov_len = buf_size; 906*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 907068f8a7eSTamas Berghammer } 908068f8a7eSTamas Berghammer 909c7512fdcSPavel Labath Error 910c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) 911068f8a7eSTamas Berghammer { 912c7512fdcSPavel Labath int regset = NT_FPREGSET; 913c7512fdcSPavel Labath struct iovec ioVec; 914c7512fdcSPavel Labath Error error; 915c7512fdcSPavel Labath 916c7512fdcSPavel Labath ioVec.iov_base = buf; 917c7512fdcSPavel Labath ioVec.iov_len = buf_size; 918*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 919068f8a7eSTamas Berghammer } 920068f8a7eSTamas Berghammer 921c7512fdcSPavel Labath Error 922c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) 923068f8a7eSTamas Berghammer { 924c7512fdcSPavel Labath int regset = NT_FPREGSET; 925c7512fdcSPavel Labath struct iovec ioVec; 926c7512fdcSPavel Labath Error error; 927c7512fdcSPavel Labath 928c7512fdcSPavel Labath ioVec.iov_base = buf; 929c7512fdcSPavel Labath ioVec.iov_len = buf_size; 930*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 931068f8a7eSTamas Berghammer } 932068f8a7eSTamas Berghammer 933068f8a7eSTamas Berghammer #endif // defined (__arm64__) || defined (__aarch64__) 934