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 196cec93c35STamas Berghammer uint32_t 197cec93c35STamas Berghammer NativeRegisterContextLinux_arm64::GetUserRegisterCount() const 198cec93c35STamas Berghammer { 199cec93c35STamas Berghammer uint32_t count = 0; 200cec93c35STamas Berghammer for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) 201cec93c35STamas Berghammer count += g_reg_sets_arm64[set_index].num_registers; 202cec93c35STamas Berghammer return count; 203cec93c35STamas Berghammer } 204cec93c35STamas Berghammer 205db264a6dSTamas Berghammer Error 2061e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) 2071e209fccSTamas Berghammer { 2081e209fccSTamas Berghammer Error error; 2091e209fccSTamas Berghammer 2101e209fccSTamas Berghammer if (!reg_info) 2111e209fccSTamas Berghammer { 2121e209fccSTamas Berghammer error.SetErrorString ("reg_info NULL"); 2131e209fccSTamas Berghammer return error; 2141e209fccSTamas Berghammer } 2151e209fccSTamas Berghammer 2161e209fccSTamas Berghammer const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 2171e209fccSTamas Berghammer 2181e209fccSTamas Berghammer if (IsFPR(reg)) 2191e209fccSTamas Berghammer { 220068f8a7eSTamas Berghammer error = ReadFPR(); 221068f8a7eSTamas Berghammer if (error.Fail()) 2221e209fccSTamas Berghammer return error; 2231e209fccSTamas Berghammer } 2241e209fccSTamas Berghammer else 2251e209fccSTamas Berghammer { 2261e209fccSTamas Berghammer uint32_t full_reg = reg; 2271e209fccSTamas Berghammer bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 2281e209fccSTamas Berghammer 2291e209fccSTamas Berghammer if (is_subreg) 2301e209fccSTamas Berghammer { 2311e209fccSTamas Berghammer // Read the full aligned 64-bit register. 2321e209fccSTamas Berghammer full_reg = reg_info->invalidate_regs[0]; 2331e209fccSTamas Berghammer } 2341e209fccSTamas Berghammer 2351e209fccSTamas Berghammer error = ReadRegisterRaw(full_reg, reg_value); 2361e209fccSTamas Berghammer 2371e209fccSTamas Berghammer if (error.Success ()) 2381e209fccSTamas Berghammer { 2391e209fccSTamas Berghammer // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. 2401e209fccSTamas Berghammer if (is_subreg && (reg_info->byte_offset & 0x1)) 2411e209fccSTamas Berghammer reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); 2421e209fccSTamas Berghammer 2431e209fccSTamas Berghammer // If our return byte size was greater than the return value reg size, then 2441e209fccSTamas Berghammer // use the type specified by reg_info rather than the uint64_t default 2451e209fccSTamas Berghammer if (reg_value.GetByteSize() > reg_info->byte_size) 2461e209fccSTamas Berghammer reg_value.SetType(reg_info); 2471e209fccSTamas Berghammer } 2481e209fccSTamas Berghammer return error; 2491e209fccSTamas Berghammer } 2501e209fccSTamas Berghammer 2511e209fccSTamas Berghammer // Get pointer to m_fpr variable and set the data from it. 2521e209fccSTamas Berghammer assert (reg_info->byte_offset < sizeof m_fpr); 2531e209fccSTamas Berghammer uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; 254cec93c35STamas Berghammer reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, eByteOrderLittle, error); 2551e209fccSTamas Berghammer 2561e209fccSTamas Berghammer return error; 2571e209fccSTamas Berghammer } 2581e209fccSTamas Berghammer 259db264a6dSTamas Berghammer Error 2601e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) 2611e209fccSTamas Berghammer { 2621e209fccSTamas Berghammer if (!reg_info) 2631e209fccSTamas Berghammer return Error ("reg_info NULL"); 2641e209fccSTamas Berghammer 2651e209fccSTamas Berghammer const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 2661e209fccSTamas Berghammer if (reg_index == LLDB_INVALID_REGNUM) 2671e209fccSTamas Berghammer return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>"); 2681e209fccSTamas Berghammer 2691e209fccSTamas Berghammer if (IsGPR(reg_index)) 2701e209fccSTamas Berghammer return WriteRegisterRaw(reg_index, reg_value); 2711e209fccSTamas Berghammer 2721e209fccSTamas Berghammer if (IsFPR(reg_index)) 2731e209fccSTamas Berghammer { 2741e209fccSTamas Berghammer // Get pointer to m_fpr variable and set the data to it. 2751e209fccSTamas Berghammer assert (reg_info->byte_offset < sizeof(m_fpr)); 2761e209fccSTamas Berghammer uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset; 2771e209fccSTamas Berghammer switch (reg_info->byte_size) 2781e209fccSTamas Berghammer { 2791e209fccSTamas Berghammer case 2: 2801e209fccSTamas Berghammer *(uint16_t *)dst = reg_value.GetAsUInt16(); 2811e209fccSTamas Berghammer break; 2821e209fccSTamas Berghammer case 4: 2831e209fccSTamas Berghammer *(uint32_t *)dst = reg_value.GetAsUInt32(); 2841e209fccSTamas Berghammer break; 2851e209fccSTamas Berghammer case 8: 2861e209fccSTamas Berghammer *(uint64_t *)dst = reg_value.GetAsUInt64(); 2871e209fccSTamas Berghammer break; 2881e209fccSTamas Berghammer default: 2891e209fccSTamas Berghammer assert(false && "Unhandled data size."); 2901e209fccSTamas Berghammer return Error ("unhandled register data size %" PRIu32, reg_info->byte_size); 2911e209fccSTamas Berghammer } 2921e209fccSTamas Berghammer 293068f8a7eSTamas Berghammer Error error = WriteFPR(); 294068f8a7eSTamas Berghammer if (error.Fail()) 295068f8a7eSTamas Berghammer return error; 2961e209fccSTamas Berghammer 2971e209fccSTamas Berghammer return Error (); 2981e209fccSTamas Berghammer } 2991e209fccSTamas Berghammer 3001e209fccSTamas Berghammer return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown"); 3011e209fccSTamas Berghammer } 3021e209fccSTamas Berghammer 303db264a6dSTamas Berghammer Error 3041e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) 3051e209fccSTamas Berghammer { 3061e209fccSTamas Berghammer Error error; 3071e209fccSTamas Berghammer 308db264a6dSTamas Berghammer data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); 3091e209fccSTamas Berghammer if (!data_sp) 3101e209fccSTamas Berghammer return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE); 3111e209fccSTamas Berghammer 312068f8a7eSTamas Berghammer error = ReadGPR(); 313068f8a7eSTamas Berghammer if (error.Fail()) 3141e209fccSTamas Berghammer return error; 3151e209fccSTamas Berghammer 316068f8a7eSTamas Berghammer error = ReadFPR(); 317068f8a7eSTamas Berghammer if (error.Fail()) 3181e209fccSTamas Berghammer return error; 3191e209fccSTamas Berghammer 3201e209fccSTamas Berghammer uint8_t *dst = data_sp->GetBytes (); 3211e209fccSTamas Berghammer if (dst == nullptr) 3221e209fccSTamas Berghammer { 3231e209fccSTamas Berghammer error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE); 3241e209fccSTamas Berghammer return error; 3251e209fccSTamas Berghammer } 3261e209fccSTamas Berghammer 3271e209fccSTamas Berghammer ::memcpy (dst, &m_gpr_arm64, GetGPRSize()); 3281e209fccSTamas Berghammer dst += GetGPRSize(); 3291e209fccSTamas Berghammer ::memcpy (dst, &m_fpr, sizeof(m_fpr)); 3301e209fccSTamas Berghammer 3311e209fccSTamas Berghammer return error; 3321e209fccSTamas Berghammer } 3331e209fccSTamas Berghammer 334db264a6dSTamas Berghammer Error 3351e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) 3361e209fccSTamas Berghammer { 3371e209fccSTamas Berghammer Error error; 3381e209fccSTamas Berghammer 3391e209fccSTamas Berghammer if (!data_sp) 3401e209fccSTamas Berghammer { 3411e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__); 3421e209fccSTamas Berghammer return error; 3431e209fccSTamas Berghammer } 3441e209fccSTamas Berghammer 3451e209fccSTamas Berghammer if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) 3461e209fccSTamas Berghammer { 3471e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ()); 3481e209fccSTamas Berghammer return error; 3491e209fccSTamas Berghammer } 3501e209fccSTamas Berghammer 3511e209fccSTamas Berghammer 3521e209fccSTamas Berghammer uint8_t *src = data_sp->GetBytes (); 3531e209fccSTamas Berghammer if (src == nullptr) 3541e209fccSTamas Berghammer { 3551e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); 3561e209fccSTamas Berghammer return error; 3571e209fccSTamas Berghammer } 3581e209fccSTamas Berghammer ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ()); 3591e209fccSTamas Berghammer 360068f8a7eSTamas Berghammer error = WriteGPR(); 361068f8a7eSTamas Berghammer if (error.Fail()) 3621e209fccSTamas Berghammer return error; 3631e209fccSTamas Berghammer 3641e209fccSTamas Berghammer src += GetRegisterInfoInterface ().GetGPRSize (); 3651e209fccSTamas Berghammer ::memcpy (&m_fpr, src, sizeof(m_fpr)); 3661e209fccSTamas Berghammer 367068f8a7eSTamas Berghammer error = WriteFPR(); 3681e209fccSTamas Berghammer if (error.Fail()) 3691e209fccSTamas Berghammer return error; 3701e209fccSTamas Berghammer 3711e209fccSTamas Berghammer return error; 3721e209fccSTamas Berghammer } 3731e209fccSTamas Berghammer 3741e209fccSTamas Berghammer bool 3751e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const 3761e209fccSTamas Berghammer { 3771e209fccSTamas Berghammer return reg <= m_reg_info.last_gpr; // GPR's come first. 3781e209fccSTamas Berghammer } 3791e209fccSTamas Berghammer 3801e209fccSTamas Berghammer bool 3811e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const 3821e209fccSTamas Berghammer { 3831e209fccSTamas Berghammer return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 3841e209fccSTamas Berghammer } 3851e209fccSTamas Berghammer 386ea8c25a8SOmair Javaid uint32_t 387ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) 388ea8c25a8SOmair Javaid { 389ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 390ea8c25a8SOmair Javaid 391ea8c25a8SOmair Javaid if (log) 392ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 393ea8c25a8SOmair Javaid 394*3a56363aSOmair Javaid Error error; 395ea8c25a8SOmair Javaid 396*3a56363aSOmair Javaid // Read hardware breakpoint and watchpoint information. 397*3a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 398*3a56363aSOmair Javaid 399*3a56363aSOmair Javaid if (error.Fail()) 400*3a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 401*3a56363aSOmair Javaid 402*3a56363aSOmair Javaid uint32_t control_value = 0, bp_index = 0; 403ea8c25a8SOmair Javaid 404ea8c25a8SOmair Javaid // Check if size has a valid hardware breakpoint length. 405ea8c25a8SOmair Javaid if (size != 4) 406ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware breakpoint 407ea8c25a8SOmair Javaid 408ea8c25a8SOmair Javaid // Check 4-byte alignment for hardware breakpoint target address. 409ea8c25a8SOmair Javaid if (addr & 0x03) 410ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. 411ea8c25a8SOmair Javaid 412ea8c25a8SOmair Javaid // Setup control value 413ea8c25a8SOmair Javaid control_value = 0; 414ea8c25a8SOmair Javaid control_value |= ((1 << size) - 1) << 5; 415ea8c25a8SOmair Javaid control_value |= (2 << 1) | 1; 416ea8c25a8SOmair Javaid 417ea8c25a8SOmair Javaid // Iterate over stored hardware breakpoints 418ea8c25a8SOmair Javaid // Find a free bp_index or update reference count if duplicate. 419ea8c25a8SOmair Javaid bp_index = LLDB_INVALID_INDEX32; 420ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hbp_supported; i++) 421ea8c25a8SOmair Javaid { 422ea8c25a8SOmair Javaid if ((m_hbr_regs[i].control & 1) == 0) 423ea8c25a8SOmair Javaid { 424ea8c25a8SOmair Javaid bp_index = i; // Mark last free slot 425ea8c25a8SOmair Javaid } 426ea8c25a8SOmair Javaid else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value) 427ea8c25a8SOmair Javaid { 428ea8c25a8SOmair Javaid bp_index = i; // Mark duplicate index 429ea8c25a8SOmair Javaid break; // Stop searching here 430ea8c25a8SOmair Javaid } 431ea8c25a8SOmair Javaid } 432ea8c25a8SOmair Javaid 433ea8c25a8SOmair Javaid if (bp_index == LLDB_INVALID_INDEX32) 434ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; 435ea8c25a8SOmair Javaid 436ea8c25a8SOmair Javaid // Add new or update existing watchpoint 437ea8c25a8SOmair Javaid if ((m_hbr_regs[bp_index].control & 1) == 0) 438ea8c25a8SOmair Javaid { 439ea8c25a8SOmair Javaid m_hbr_regs[bp_index].address = addr; 440ea8c25a8SOmair Javaid m_hbr_regs[bp_index].control = control_value; 441ea8c25a8SOmair Javaid m_hbr_regs[bp_index].refcount = 1; 442ea8c25a8SOmair Javaid 4431fd2a8cfSOmair Javaid // PTRACE call to set corresponding hardware breakpoint register. 444*3a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK); 445*3a56363aSOmair Javaid 446*3a56363aSOmair Javaid if (error.Fail()) 447*3a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 448ea8c25a8SOmair Javaid } 449ea8c25a8SOmair Javaid else 450ea8c25a8SOmair Javaid m_hbr_regs[bp_index].refcount++; 451ea8c25a8SOmair Javaid 452ea8c25a8SOmair Javaid return bp_index; 453ea8c25a8SOmair Javaid } 454ea8c25a8SOmair Javaid 455ea8c25a8SOmair Javaid bool 456ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx) 457ea8c25a8SOmair Javaid { 458ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 459ea8c25a8SOmair Javaid 460ea8c25a8SOmair Javaid if (log) 461ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 462ea8c25a8SOmair Javaid 463*3a56363aSOmair Javaid Error error; 464*3a56363aSOmair Javaid 4651fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 466*3a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 467*3a56363aSOmair Javaid 468*3a56363aSOmair Javaid if (error.Fail()) 469*3a56363aSOmair Javaid return false; 4701fd2a8cfSOmair Javaid 471ea8c25a8SOmair Javaid if (hw_idx >= m_max_hbp_supported) 472ea8c25a8SOmair Javaid return false; 473ea8c25a8SOmair Javaid 474ea8c25a8SOmair Javaid // Update reference count if multiple references. 475ea8c25a8SOmair Javaid if (m_hbr_regs[hw_idx].refcount > 1) 476ea8c25a8SOmair Javaid { 477ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].refcount--; 478ea8c25a8SOmair Javaid return true; 479ea8c25a8SOmair Javaid } 480ea8c25a8SOmair Javaid else if (m_hbr_regs[hw_idx].refcount == 1) 481ea8c25a8SOmair Javaid { 482ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].control &= ~1; 483ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].address = 0; 484ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].refcount = 0; 485ea8c25a8SOmair Javaid 4861fd2a8cfSOmair Javaid // PTRACE call to clear corresponding hardware breakpoint register. 4871fd2a8cfSOmair Javaid WriteHardwareDebugRegs(eDREGTypeBREAK); 488*3a56363aSOmair Javaid 489*3a56363aSOmair Javaid if (error.Fail()) 490*3a56363aSOmair Javaid return false; 491*3a56363aSOmair Javaid 492*3a56363aSOmair Javaid return true; 493ea8c25a8SOmair Javaid } 494ea8c25a8SOmair Javaid 495ea8c25a8SOmair Javaid return false; 496ea8c25a8SOmair Javaid } 497ea8c25a8SOmair Javaid 498ea8c25a8SOmair Javaid uint32_t 499ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints () 500ea8c25a8SOmair Javaid { 501ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 502ea8c25a8SOmair Javaid 503ea8c25a8SOmair Javaid if (log) 504ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 505ea8c25a8SOmair Javaid 506*3a56363aSOmair Javaid Error error; 507*3a56363aSOmair Javaid 5081fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 509*3a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 510*3a56363aSOmair Javaid 511*3a56363aSOmair Javaid if (error.Fail()) 512*3a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 5131fd2a8cfSOmair Javaid 514ea8c25a8SOmair Javaid return m_max_hwp_supported; 515ea8c25a8SOmair Javaid } 516ea8c25a8SOmair Javaid 517ea8c25a8SOmair Javaid uint32_t 518ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) 519ea8c25a8SOmair Javaid { 520ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 521ea8c25a8SOmair Javaid 522ea8c25a8SOmair Javaid if (log) 523ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 524ea8c25a8SOmair Javaid 525*3a56363aSOmair Javaid Error error; 526ea8c25a8SOmair Javaid 527*3a56363aSOmair Javaid // Read hardware breakpoint and watchpoint information. 528*3a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 529*3a56363aSOmair Javaid 530*3a56363aSOmair Javaid if (error.Fail()) 531*3a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 532*3a56363aSOmair Javaid 533*3a56363aSOmair Javaid uint32_t control_value = 0, wp_index = 0; 534ea8c25a8SOmair Javaid 5351fd2a8cfSOmair Javaid // Check if we are setting watchpoint other than read/write/access 5361fd2a8cfSOmair Javaid // Also update watchpoint flag to match AArch64 write-read bit configuration. 5371fd2a8cfSOmair Javaid switch (watch_flags) 5381fd2a8cfSOmair Javaid { 5391fd2a8cfSOmair Javaid case 1: 5401fd2a8cfSOmair Javaid watch_flags = 2; 5411fd2a8cfSOmair Javaid break; 5421fd2a8cfSOmair Javaid case 2: 5431fd2a8cfSOmair Javaid watch_flags = 1; 5441fd2a8cfSOmair Javaid break; 5451fd2a8cfSOmair Javaid case 3: 5461fd2a8cfSOmair Javaid break; 5471fd2a8cfSOmair Javaid default: 5481fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 5491fd2a8cfSOmair Javaid } 550ea8c25a8SOmair Javaid 551ea8c25a8SOmair Javaid // Check if size has a valid hardware watchpoint length. 552ea8c25a8SOmair Javaid if (size != 1 && size != 2 && size != 4 && size != 8) 5531fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 554ea8c25a8SOmair Javaid 555ea8c25a8SOmair Javaid // Check 8-byte alignment for hardware watchpoint target address. 556ea8c25a8SOmair Javaid // TODO: Add support for watching un-aligned addresses 557ea8c25a8SOmair Javaid if (addr & 0x07) 5581fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 559ea8c25a8SOmair Javaid 560ea8c25a8SOmair Javaid // Setup control value 561ea8c25a8SOmair Javaid control_value = watch_flags << 3; 562ea8c25a8SOmair Javaid control_value |= ((1 << size) - 1) << 5; 563ea8c25a8SOmair Javaid control_value |= (2 << 1) | 1; 564ea8c25a8SOmair Javaid 565ea8c25a8SOmair Javaid // Iterate over stored watchpoints 566ea8c25a8SOmair Javaid // Find a free wp_index or update reference count if duplicate. 567ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 568ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 569ea8c25a8SOmair Javaid { 570ea8c25a8SOmair Javaid if ((m_hwp_regs[i].control & 1) == 0) 571ea8c25a8SOmair Javaid { 572ea8c25a8SOmair Javaid wp_index = i; // Mark last free slot 573ea8c25a8SOmair Javaid } 574ea8c25a8SOmair Javaid else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value) 575ea8c25a8SOmair Javaid { 576ea8c25a8SOmair Javaid wp_index = i; // Mark duplicate index 577ea8c25a8SOmair Javaid break; // Stop searching here 578ea8c25a8SOmair Javaid } 579ea8c25a8SOmair Javaid } 580ea8c25a8SOmair Javaid 581ea8c25a8SOmair Javaid if (wp_index == LLDB_INVALID_INDEX32) 582ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; 583ea8c25a8SOmair Javaid 584ea8c25a8SOmair Javaid // Add new or update existing watchpoint 585ea8c25a8SOmair Javaid if ((m_hwp_regs[wp_index].control & 1) == 0) 586ea8c25a8SOmair Javaid { 5871fd2a8cfSOmair Javaid // Update watchpoint in local cache 588ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = addr; 589ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control = control_value; 590ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount = 1; 591ea8c25a8SOmair Javaid 592ea8c25a8SOmair Javaid // PTRACE call to set corresponding watchpoint register. 593*3a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 594*3a56363aSOmair Javaid 595*3a56363aSOmair Javaid if (error.Fail()) 596*3a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 597ea8c25a8SOmair Javaid } 598ea8c25a8SOmair Javaid else 599ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount++; 600ea8c25a8SOmair Javaid 601ea8c25a8SOmair Javaid return wp_index; 602ea8c25a8SOmair Javaid } 603ea8c25a8SOmair Javaid 604ea8c25a8SOmair Javaid bool 605ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index) 606ea8c25a8SOmair Javaid { 607ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 608ea8c25a8SOmair Javaid 609ea8c25a8SOmair Javaid if (log) 610ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 611ea8c25a8SOmair Javaid 612*3a56363aSOmair Javaid Error error; 613*3a56363aSOmair Javaid 6141fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 615*3a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 616*3a56363aSOmair Javaid 617*3a56363aSOmair Javaid if (error.Fail()) 618*3a56363aSOmair Javaid return false; 619ea8c25a8SOmair Javaid 620ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 621ea8c25a8SOmair Javaid return false; 622ea8c25a8SOmair Javaid 623ea8c25a8SOmair Javaid // Update reference count if multiple references. 624ea8c25a8SOmair Javaid if (m_hwp_regs[wp_index].refcount > 1) 625ea8c25a8SOmair Javaid { 626ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount--; 627ea8c25a8SOmair Javaid return true; 628ea8c25a8SOmair Javaid } 629ea8c25a8SOmair Javaid else if (m_hwp_regs[wp_index].refcount == 1) 630ea8c25a8SOmair Javaid { 6311fd2a8cfSOmair Javaid // Update watchpoint in local cache 632ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control &= ~1; 633ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = 0; 634ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount = 0; 635ea8c25a8SOmair Javaid 6361fd2a8cfSOmair Javaid // Ptrace call to update hardware debug registers 637*3a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 638*3a56363aSOmair Javaid 639*3a56363aSOmair Javaid if (error.Fail()) 640*3a56363aSOmair Javaid return false; 641*3a56363aSOmair Javaid 642ea8c25a8SOmair Javaid return true; 643ea8c25a8SOmair Javaid } 644ea8c25a8SOmair Javaid 645ea8c25a8SOmair Javaid return false; 646ea8c25a8SOmair Javaid } 647ea8c25a8SOmair Javaid 648ea8c25a8SOmair Javaid Error 649ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints () 650ea8c25a8SOmair Javaid { 651ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 652ea8c25a8SOmair Javaid 653ea8c25a8SOmair Javaid if (log) 654ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 655ea8c25a8SOmair Javaid 656*3a56363aSOmair Javaid Error error; 657*3a56363aSOmair Javaid 6581fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 659*3a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 660*3a56363aSOmair Javaid 661*3a56363aSOmair Javaid if (error.Fail()) 662*3a56363aSOmair Javaid return error; 663ea8c25a8SOmair Javaid 664ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 665ea8c25a8SOmair Javaid { 666ea8c25a8SOmair Javaid if (m_hwp_regs[i].control & 0x01) 667ea8c25a8SOmair Javaid { 6681fd2a8cfSOmair Javaid // Clear watchpoints in local cache 669ea8c25a8SOmair Javaid m_hwp_regs[i].control &= ~1; 670ea8c25a8SOmair Javaid m_hwp_regs[i].address = 0; 671ea8c25a8SOmair Javaid m_hwp_regs[i].refcount = 0; 672ea8c25a8SOmair Javaid 6731fd2a8cfSOmair Javaid // Ptrace call to update hardware debug registers 674*3a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 675*3a56363aSOmair Javaid 676*3a56363aSOmair Javaid if (error.Fail()) 677*3a56363aSOmair Javaid return error; 678ea8c25a8SOmair Javaid } 679ea8c25a8SOmair Javaid } 680ea8c25a8SOmair Javaid 681ea8c25a8SOmair Javaid return Error(); 682ea8c25a8SOmair Javaid } 683ea8c25a8SOmair Javaid 684ea8c25a8SOmair Javaid uint32_t 685ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) 686ea8c25a8SOmair Javaid { 687ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 688ea8c25a8SOmair Javaid 689ea8c25a8SOmair Javaid if (log) 690ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 691ea8c25a8SOmair Javaid switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) 692ea8c25a8SOmair Javaid { 693ea8c25a8SOmair Javaid case 0x01: 694ea8c25a8SOmair Javaid return 1; 695ea8c25a8SOmair Javaid case 0x03: 696ea8c25a8SOmair Javaid return 2; 697ea8c25a8SOmair Javaid case 0x0f: 698ea8c25a8SOmair Javaid return 4; 699ea8c25a8SOmair Javaid case 0xff: 700ea8c25a8SOmair Javaid return 8; 701ea8c25a8SOmair Javaid default: 702ea8c25a8SOmair Javaid return 0; 703ea8c25a8SOmair Javaid } 704ea8c25a8SOmair Javaid } 705ea8c25a8SOmair Javaid bool 706ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) 707ea8c25a8SOmair Javaid { 708ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 709ea8c25a8SOmair Javaid 710ea8c25a8SOmair Javaid if (log) 711ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 712ea8c25a8SOmair Javaid 713ea8c25a8SOmair Javaid if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 714ea8c25a8SOmair Javaid return true; 715ea8c25a8SOmair Javaid else 716ea8c25a8SOmair Javaid return false; 717ea8c25a8SOmair Javaid } 718ea8c25a8SOmair Javaid 719ea8c25a8SOmair Javaid Error 720ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) 721ea8c25a8SOmair Javaid { 722ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 723ea8c25a8SOmair Javaid 724ea8c25a8SOmair Javaid if (log) 725ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 726ea8c25a8SOmair Javaid 727ea8c25a8SOmair Javaid uint32_t watch_size; 728ea8c25a8SOmair Javaid lldb::addr_t watch_addr; 729ea8c25a8SOmair Javaid 730ea8c25a8SOmair Javaid for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) 731ea8c25a8SOmair Javaid { 732ea8c25a8SOmair Javaid watch_size = GetWatchpointSize (wp_index); 733ea8c25a8SOmair Javaid watch_addr = m_hwp_regs[wp_index].address; 734ea8c25a8SOmair Javaid 735ea8c25a8SOmair Javaid if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) 736ea8c25a8SOmair Javaid && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) 737ea8c25a8SOmair Javaid { 738ea8c25a8SOmair Javaid return Error(); 739ea8c25a8SOmair Javaid } 740ea8c25a8SOmair Javaid } 741ea8c25a8SOmair Javaid 742ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 743ea8c25a8SOmair Javaid return Error(); 744ea8c25a8SOmair Javaid } 745ea8c25a8SOmair Javaid 746ea8c25a8SOmair Javaid lldb::addr_t 747ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index) 748ea8c25a8SOmair Javaid { 749ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 750ea8c25a8SOmair Javaid 751ea8c25a8SOmair Javaid if (log) 752ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 753ea8c25a8SOmair Javaid 754ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 755ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 756ea8c25a8SOmair Javaid 757ea8c25a8SOmair Javaid if (WatchpointIsEnabled(wp_index)) 758ea8c25a8SOmair Javaid return m_hwp_regs[wp_index].address; 759ea8c25a8SOmair Javaid else 760ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 761ea8c25a8SOmair Javaid } 762ea8c25a8SOmair Javaid 763068f8a7eSTamas Berghammer Error 7641fd2a8cfSOmair Javaid NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() 765ea8c25a8SOmair Javaid { 7661fd2a8cfSOmair Javaid if (!m_refresh_hwdebug_info) 7671fd2a8cfSOmair Javaid { 7681fd2a8cfSOmair Javaid return Error(); 7691fd2a8cfSOmair Javaid } 7701fd2a8cfSOmair Javaid 771c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 772ea8c25a8SOmair Javaid 773c7512fdcSPavel Labath int regset = NT_ARM_HW_WATCH; 774c7512fdcSPavel Labath struct iovec ioVec; 775c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 776c7512fdcSPavel Labath Error error; 777c7512fdcSPavel Labath 778c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 779c7512fdcSPavel Labath ioVec.iov_len = sizeof (dreg_state); 7804a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 781*3a56363aSOmair Javaid 782*3a56363aSOmair Javaid if (error.Fail()) 783*3a56363aSOmair Javaid return error; 784*3a56363aSOmair Javaid 7851fd2a8cfSOmair Javaid m_max_hwp_supported = dreg_state.dbg_info & 0xff; 786c7512fdcSPavel Labath 787c7512fdcSPavel Labath regset = NT_ARM_HW_BREAK; 7884a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 7891fd2a8cfSOmair Javaid 790*3a56363aSOmair Javaid if (error.Fail()) 791*3a56363aSOmair Javaid return error; 792*3a56363aSOmair Javaid 793*3a56363aSOmair Javaid m_max_hbp_supported = dreg_state.dbg_info & 0xff; 7941fd2a8cfSOmair Javaid m_refresh_hwdebug_info = false; 795c7512fdcSPavel Labath 796c7512fdcSPavel Labath return error; 797ea8c25a8SOmair Javaid } 798068f8a7eSTamas Berghammer 799068f8a7eSTamas Berghammer Error 8001fd2a8cfSOmair Javaid NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) 801068f8a7eSTamas Berghammer { 802c7512fdcSPavel Labath struct iovec ioVec; 803c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 804c7512fdcSPavel Labath Error error; 805c7512fdcSPavel Labath 806c7512fdcSPavel Labath memset (&dreg_state, 0, sizeof (dreg_state)); 807c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 808c7512fdcSPavel Labath ioVec.iov_len = sizeof (dreg_state); 809c7512fdcSPavel Labath 8101fd2a8cfSOmair Javaid if (hwbType == eDREGTypeWATCH) 811c7512fdcSPavel Labath { 8121fd2a8cfSOmair Javaid hwbType = NT_ARM_HW_WATCH; 8131fd2a8cfSOmair Javaid 8141fd2a8cfSOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 8151fd2a8cfSOmair Javaid { 8161fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; 8171fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; 8181fd2a8cfSOmair Javaid } 8191fd2a8cfSOmair Javaid } 8201fd2a8cfSOmair Javaid else 8211fd2a8cfSOmair Javaid { 8221fd2a8cfSOmair Javaid hwbType = NT_ARM_HW_BREAK; 8231fd2a8cfSOmair Javaid 8241fd2a8cfSOmair Javaid for (uint32_t i = 0; i < m_max_hbp_supported; i++) 8251fd2a8cfSOmair Javaid { 8261fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address; 8271fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control; 8281fd2a8cfSOmair Javaid } 829068f8a7eSTamas Berghammer } 830068f8a7eSTamas Berghammer 8311fd2a8cfSOmair Javaid return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &hwbType, &ioVec, ioVec.iov_len); 832c7512fdcSPavel Labath } 833c7512fdcSPavel Labath 834c7512fdcSPavel Labath Error 835c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset, 836068f8a7eSTamas Berghammer const char* reg_name, 837068f8a7eSTamas Berghammer uint32_t size, 838068f8a7eSTamas Berghammer RegisterValue &value) 839068f8a7eSTamas Berghammer { 840c7512fdcSPavel Labath Error error; 841c7512fdcSPavel Labath if (offset > sizeof(struct user_pt_regs)) 842c7512fdcSPavel Labath { 843c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 844c7512fdcSPavel Labath if (offset > sizeof(struct user_fpsimd_state)) 845c7512fdcSPavel Labath { 846c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 847c7512fdcSPavel Labath return error; 848c7512fdcSPavel Labath } 849c7512fdcSPavel Labath elf_fpregset_t regs; 850c7512fdcSPavel Labath int regset = NT_FPREGSET; 851c7512fdcSPavel Labath struct iovec ioVec; 852c7512fdcSPavel Labath 853c7512fdcSPavel Labath ioVec.iov_base = ®s; 854c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 8554a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 8564a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 857c7512fdcSPavel Labath if (error.Success()) 858c7512fdcSPavel Labath { 859c7512fdcSPavel Labath ArchSpec arch; 860c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 861c7512fdcSPavel Labath value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, arch.GetByteOrder()); 862c7512fdcSPavel Labath else 863c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 864c7512fdcSPavel Labath } 865c7512fdcSPavel Labath } 866c7512fdcSPavel Labath else 867c7512fdcSPavel Labath { 868c7512fdcSPavel Labath elf_gregset_t regs; 869c7512fdcSPavel Labath int regset = NT_PRSTATUS; 870c7512fdcSPavel Labath struct iovec ioVec; 871c7512fdcSPavel Labath 872c7512fdcSPavel Labath ioVec.iov_base = ®s; 873c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 8744a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 8754a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 876c7512fdcSPavel Labath if (error.Success()) 877c7512fdcSPavel Labath { 878c7512fdcSPavel Labath ArchSpec arch; 879c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 880c7512fdcSPavel Labath value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder()); 881c7512fdcSPavel Labath else 882c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 883c7512fdcSPavel Labath } 884c7512fdcSPavel Labath } 885c7512fdcSPavel Labath return error; 886068f8a7eSTamas Berghammer } 887068f8a7eSTamas Berghammer 888c7512fdcSPavel Labath Error 889c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset, 890068f8a7eSTamas Berghammer const char* reg_name, 891068f8a7eSTamas Berghammer const RegisterValue &value) 892068f8a7eSTamas Berghammer { 893c7512fdcSPavel Labath Error error; 894c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 895c7512fdcSPavel Labath if (offset > sizeof(struct user_pt_regs)) 896c7512fdcSPavel Labath { 897c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 898c7512fdcSPavel Labath if (offset > sizeof(struct user_fpsimd_state)) 899c7512fdcSPavel Labath { 900c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 901c7512fdcSPavel Labath return error; 902c7512fdcSPavel Labath } 903c7512fdcSPavel Labath elf_fpregset_t regs; 904c7512fdcSPavel Labath int regset = NT_FPREGSET; 905c7512fdcSPavel Labath struct iovec ioVec; 906c7512fdcSPavel Labath 907c7512fdcSPavel Labath ioVec.iov_base = ®s; 908c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 9094a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 910c7512fdcSPavel Labath 911c7512fdcSPavel Labath if (error.Success()) 912c7512fdcSPavel Labath { 913c7512fdcSPavel Labath ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 16); 9144a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 915c7512fdcSPavel Labath } 916c7512fdcSPavel Labath } 917c7512fdcSPavel Labath else 918c7512fdcSPavel Labath { 919c7512fdcSPavel Labath elf_gregset_t regs; 920c7512fdcSPavel Labath int regset = NT_PRSTATUS; 921c7512fdcSPavel Labath struct iovec ioVec; 922c7512fdcSPavel Labath 923c7512fdcSPavel Labath ioVec.iov_base = ®s; 924c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 9254a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 926c7512fdcSPavel Labath if (error.Success()) 927c7512fdcSPavel Labath { 928c7512fdcSPavel Labath ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 8); 9294a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 930c7512fdcSPavel Labath } 931c7512fdcSPavel Labath } 932c7512fdcSPavel Labath return error; 933068f8a7eSTamas Berghammer } 934068f8a7eSTamas Berghammer 935c7512fdcSPavel Labath Error 936c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) 937068f8a7eSTamas Berghammer { 938c7512fdcSPavel Labath int regset = NT_PRSTATUS; 939c7512fdcSPavel Labath struct iovec ioVec; 940c7512fdcSPavel Labath Error error; 941c7512fdcSPavel Labath 942c7512fdcSPavel Labath ioVec.iov_base = buf; 943c7512fdcSPavel Labath ioVec.iov_len = buf_size; 9444a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 945068f8a7eSTamas Berghammer } 946068f8a7eSTamas Berghammer 947c7512fdcSPavel Labath Error 948c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) 949068f8a7eSTamas Berghammer { 950c7512fdcSPavel Labath int regset = NT_PRSTATUS; 951c7512fdcSPavel Labath struct iovec ioVec; 952c7512fdcSPavel Labath Error error; 953c7512fdcSPavel Labath 954c7512fdcSPavel Labath ioVec.iov_base = buf; 955c7512fdcSPavel Labath ioVec.iov_len = buf_size; 9564a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 957068f8a7eSTamas Berghammer } 958068f8a7eSTamas Berghammer 959c7512fdcSPavel Labath Error 960c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) 961068f8a7eSTamas Berghammer { 962c7512fdcSPavel Labath int regset = NT_FPREGSET; 963c7512fdcSPavel Labath struct iovec ioVec; 964c7512fdcSPavel Labath Error error; 965c7512fdcSPavel Labath 966c7512fdcSPavel Labath ioVec.iov_base = buf; 967c7512fdcSPavel Labath ioVec.iov_len = buf_size; 9684a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 969068f8a7eSTamas Berghammer } 970068f8a7eSTamas Berghammer 971c7512fdcSPavel Labath Error 972c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) 973068f8a7eSTamas Berghammer { 974c7512fdcSPavel Labath int regset = NT_FPREGSET; 975c7512fdcSPavel Labath struct iovec ioVec; 976c7512fdcSPavel Labath Error error; 977c7512fdcSPavel Labath 978c7512fdcSPavel Labath ioVec.iov_base = buf; 979c7512fdcSPavel Labath ioVec.iov_len = buf_size; 9804a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 981068f8a7eSTamas Berghammer } 982068f8a7eSTamas Berghammer 983068f8a7eSTamas Berghammer #endif // defined (__arm64__) || defined (__aarch64__) 984