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. 252c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 253c40e7b17STamas Berghammer assert (fpr_offset < sizeof m_fpr); 254c40e7b17STamas Berghammer uint8_t *src = (uint8_t *)&m_fpr + fpr_offset; 255cec93c35STamas Berghammer reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, eByteOrderLittle, error); 2561e209fccSTamas Berghammer 2571e209fccSTamas Berghammer return error; 2581e209fccSTamas Berghammer } 2591e209fccSTamas Berghammer 260db264a6dSTamas Berghammer Error 2611e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) 2621e209fccSTamas Berghammer { 2631e209fccSTamas Berghammer if (!reg_info) 2641e209fccSTamas Berghammer return Error ("reg_info NULL"); 2651e209fccSTamas Berghammer 2661e209fccSTamas Berghammer const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 2671e209fccSTamas Berghammer if (reg_index == LLDB_INVALID_REGNUM) 2681e209fccSTamas Berghammer return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>"); 2691e209fccSTamas Berghammer 2701e209fccSTamas Berghammer if (IsGPR(reg_index)) 2711e209fccSTamas Berghammer return WriteRegisterRaw(reg_index, reg_value); 2721e209fccSTamas Berghammer 2731e209fccSTamas Berghammer if (IsFPR(reg_index)) 2741e209fccSTamas Berghammer { 2751e209fccSTamas Berghammer // Get pointer to m_fpr variable and set the data to it. 276c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 277c40e7b17STamas Berghammer assert (fpr_offset < sizeof m_fpr); 278c40e7b17STamas Berghammer uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset; 2791e209fccSTamas Berghammer switch (reg_info->byte_size) 2801e209fccSTamas Berghammer { 2811e209fccSTamas Berghammer case 2: 2821e209fccSTamas Berghammer *(uint16_t *)dst = reg_value.GetAsUInt16(); 2831e209fccSTamas Berghammer break; 2841e209fccSTamas Berghammer case 4: 2851e209fccSTamas Berghammer *(uint32_t *)dst = reg_value.GetAsUInt32(); 2861e209fccSTamas Berghammer break; 2871e209fccSTamas Berghammer case 8: 2881e209fccSTamas Berghammer *(uint64_t *)dst = reg_value.GetAsUInt64(); 2891e209fccSTamas Berghammer break; 2901e209fccSTamas Berghammer default: 2911e209fccSTamas Berghammer assert(false && "Unhandled data size."); 2921e209fccSTamas Berghammer return Error ("unhandled register data size %" PRIu32, reg_info->byte_size); 2931e209fccSTamas Berghammer } 2941e209fccSTamas Berghammer 295068f8a7eSTamas Berghammer Error error = WriteFPR(); 296068f8a7eSTamas Berghammer if (error.Fail()) 297068f8a7eSTamas Berghammer return error; 2981e209fccSTamas Berghammer 2991e209fccSTamas Berghammer return Error (); 3001e209fccSTamas Berghammer } 3011e209fccSTamas Berghammer 3021e209fccSTamas Berghammer return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown"); 3031e209fccSTamas Berghammer } 3041e209fccSTamas Berghammer 305db264a6dSTamas Berghammer Error 3061e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) 3071e209fccSTamas Berghammer { 3081e209fccSTamas Berghammer Error error; 3091e209fccSTamas Berghammer 310db264a6dSTamas Berghammer data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); 3111e209fccSTamas Berghammer if (!data_sp) 3121e209fccSTamas Berghammer return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE); 3131e209fccSTamas Berghammer 314068f8a7eSTamas Berghammer error = ReadGPR(); 315068f8a7eSTamas Berghammer if (error.Fail()) 3161e209fccSTamas Berghammer return error; 3171e209fccSTamas Berghammer 318068f8a7eSTamas Berghammer error = ReadFPR(); 319068f8a7eSTamas Berghammer if (error.Fail()) 3201e209fccSTamas Berghammer return error; 3211e209fccSTamas Berghammer 3221e209fccSTamas Berghammer uint8_t *dst = data_sp->GetBytes (); 3231e209fccSTamas Berghammer if (dst == nullptr) 3241e209fccSTamas Berghammer { 3251e209fccSTamas Berghammer error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE); 3261e209fccSTamas Berghammer return error; 3271e209fccSTamas Berghammer } 3281e209fccSTamas Berghammer 3291e209fccSTamas Berghammer ::memcpy (dst, &m_gpr_arm64, GetGPRSize()); 3301e209fccSTamas Berghammer dst += GetGPRSize(); 3311e209fccSTamas Berghammer ::memcpy (dst, &m_fpr, sizeof(m_fpr)); 3321e209fccSTamas Berghammer 3331e209fccSTamas Berghammer return error; 3341e209fccSTamas Berghammer } 3351e209fccSTamas Berghammer 336db264a6dSTamas Berghammer Error 3371e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) 3381e209fccSTamas Berghammer { 3391e209fccSTamas Berghammer Error error; 3401e209fccSTamas Berghammer 3411e209fccSTamas Berghammer if (!data_sp) 3421e209fccSTamas Berghammer { 3431e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__); 3441e209fccSTamas Berghammer return error; 3451e209fccSTamas Berghammer } 3461e209fccSTamas Berghammer 3471e209fccSTamas Berghammer if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) 3481e209fccSTamas Berghammer { 3491e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ()); 3501e209fccSTamas Berghammer return error; 3511e209fccSTamas Berghammer } 3521e209fccSTamas Berghammer 3531e209fccSTamas Berghammer 3541e209fccSTamas Berghammer uint8_t *src = data_sp->GetBytes (); 3551e209fccSTamas Berghammer if (src == nullptr) 3561e209fccSTamas Berghammer { 3571e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); 3581e209fccSTamas Berghammer return error; 3591e209fccSTamas Berghammer } 3601e209fccSTamas Berghammer ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ()); 3611e209fccSTamas Berghammer 362068f8a7eSTamas Berghammer error = WriteGPR(); 363068f8a7eSTamas Berghammer if (error.Fail()) 3641e209fccSTamas Berghammer return error; 3651e209fccSTamas Berghammer 3661e209fccSTamas Berghammer src += GetRegisterInfoInterface ().GetGPRSize (); 3671e209fccSTamas Berghammer ::memcpy (&m_fpr, src, sizeof(m_fpr)); 3681e209fccSTamas Berghammer 369068f8a7eSTamas Berghammer error = WriteFPR(); 3701e209fccSTamas Berghammer if (error.Fail()) 3711e209fccSTamas Berghammer return error; 3721e209fccSTamas Berghammer 3731e209fccSTamas Berghammer return error; 3741e209fccSTamas Berghammer } 3751e209fccSTamas Berghammer 3761e209fccSTamas Berghammer bool 3771e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const 3781e209fccSTamas Berghammer { 3791e209fccSTamas Berghammer return reg <= m_reg_info.last_gpr; // GPR's come first. 3801e209fccSTamas Berghammer } 3811e209fccSTamas Berghammer 3821e209fccSTamas Berghammer bool 3831e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const 3841e209fccSTamas Berghammer { 3851e209fccSTamas Berghammer return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 3861e209fccSTamas Berghammer } 3871e209fccSTamas Berghammer 388ea8c25a8SOmair Javaid uint32_t 389ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) 390ea8c25a8SOmair Javaid { 391ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 392ea8c25a8SOmair Javaid 393ea8c25a8SOmair Javaid if (log) 394ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 395ea8c25a8SOmair Javaid 3963a56363aSOmair Javaid Error error; 397ea8c25a8SOmair Javaid 3983a56363aSOmair Javaid // Read hardware breakpoint and watchpoint information. 3993a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 4003a56363aSOmair Javaid 4013a56363aSOmair Javaid if (error.Fail()) 4023a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 4033a56363aSOmair Javaid 4043a56363aSOmair Javaid uint32_t control_value = 0, bp_index = 0; 405ea8c25a8SOmair Javaid 406ea8c25a8SOmair Javaid // Check if size has a valid hardware breakpoint length. 407ea8c25a8SOmair Javaid if (size != 4) 408ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware breakpoint 409ea8c25a8SOmair Javaid 410ea8c25a8SOmair Javaid // Check 4-byte alignment for hardware breakpoint target address. 411ea8c25a8SOmair Javaid if (addr & 0x03) 412ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. 413ea8c25a8SOmair Javaid 414ea8c25a8SOmair Javaid // Setup control value 415ea8c25a8SOmair Javaid control_value = 0; 416ea8c25a8SOmair Javaid control_value |= ((1 << size) - 1) << 5; 417ea8c25a8SOmair Javaid control_value |= (2 << 1) | 1; 418ea8c25a8SOmair Javaid 419ea8c25a8SOmair Javaid // Iterate over stored hardware breakpoints 420ea8c25a8SOmair Javaid // Find a free bp_index or update reference count if duplicate. 421ea8c25a8SOmair Javaid bp_index = LLDB_INVALID_INDEX32; 422ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hbp_supported; i++) 423ea8c25a8SOmair Javaid { 424ea8c25a8SOmair Javaid if ((m_hbr_regs[i].control & 1) == 0) 425ea8c25a8SOmair Javaid { 426ea8c25a8SOmair Javaid bp_index = i; // Mark last free slot 427ea8c25a8SOmair Javaid } 428ea8c25a8SOmair Javaid else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value) 429ea8c25a8SOmair Javaid { 430ea8c25a8SOmair Javaid bp_index = i; // Mark duplicate index 431ea8c25a8SOmair Javaid break; // Stop searching here 432ea8c25a8SOmair Javaid } 433ea8c25a8SOmair Javaid } 434ea8c25a8SOmair Javaid 435ea8c25a8SOmair Javaid if (bp_index == LLDB_INVALID_INDEX32) 436ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; 437ea8c25a8SOmair Javaid 438*f24741d9SOmair Javaid // Add new or update existing breakpoint 439ea8c25a8SOmair Javaid if ((m_hbr_regs[bp_index].control & 1) == 0) 440ea8c25a8SOmair Javaid { 441ea8c25a8SOmair Javaid m_hbr_regs[bp_index].address = addr; 442ea8c25a8SOmair Javaid m_hbr_regs[bp_index].control = control_value; 443ea8c25a8SOmair Javaid m_hbr_regs[bp_index].refcount = 1; 444ea8c25a8SOmair Javaid 4451fd2a8cfSOmair Javaid // PTRACE call to set corresponding hardware breakpoint register. 4463a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK); 4473a56363aSOmair Javaid 4483a56363aSOmair Javaid if (error.Fail()) 449*f24741d9SOmair Javaid { 450*f24741d9SOmair Javaid m_hbr_regs[bp_index].address = 0; 451*f24741d9SOmair Javaid m_hbr_regs[bp_index].control &= ~1; 452*f24741d9SOmair Javaid m_hbr_regs[bp_index].refcount = 0; 453*f24741d9SOmair Javaid 4543a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 455ea8c25a8SOmair Javaid } 456*f24741d9SOmair Javaid } 457ea8c25a8SOmair Javaid else 458ea8c25a8SOmair Javaid m_hbr_regs[bp_index].refcount++; 459ea8c25a8SOmair Javaid 460ea8c25a8SOmair Javaid return bp_index; 461ea8c25a8SOmair Javaid } 462ea8c25a8SOmair Javaid 463ea8c25a8SOmair Javaid bool 464ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx) 465ea8c25a8SOmair Javaid { 466ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 467ea8c25a8SOmair Javaid 468ea8c25a8SOmair Javaid if (log) 469ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 470ea8c25a8SOmair Javaid 4713a56363aSOmair Javaid Error error; 4723a56363aSOmair Javaid 4731fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 4743a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 4753a56363aSOmair Javaid 4763a56363aSOmair Javaid if (error.Fail()) 4773a56363aSOmair Javaid return false; 4781fd2a8cfSOmair Javaid 479ea8c25a8SOmair Javaid if (hw_idx >= m_max_hbp_supported) 480ea8c25a8SOmair Javaid return false; 481ea8c25a8SOmair Javaid 482ea8c25a8SOmair Javaid // Update reference count if multiple references. 483ea8c25a8SOmair Javaid if (m_hbr_regs[hw_idx].refcount > 1) 484ea8c25a8SOmair Javaid { 485ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].refcount--; 486ea8c25a8SOmair Javaid return true; 487ea8c25a8SOmair Javaid } 488ea8c25a8SOmair Javaid else if (m_hbr_regs[hw_idx].refcount == 1) 489ea8c25a8SOmair Javaid { 490*f24741d9SOmair Javaid // Create a backup we can revert to in case of failure. 491*f24741d9SOmair Javaid lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; 492*f24741d9SOmair Javaid uint32_t tempControl = m_hbr_regs[hw_idx].control; 493*f24741d9SOmair Javaid uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount; 494*f24741d9SOmair Javaid 495ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].control &= ~1; 496ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].address = 0; 497ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].refcount = 0; 498ea8c25a8SOmair Javaid 4991fd2a8cfSOmair Javaid // PTRACE call to clear corresponding hardware breakpoint register. 5001fd2a8cfSOmair Javaid WriteHardwareDebugRegs(eDREGTypeBREAK); 5013a56363aSOmair Javaid 5023a56363aSOmair Javaid if (error.Fail()) 503*f24741d9SOmair Javaid { 504*f24741d9SOmair Javaid m_hbr_regs[hw_idx].control = tempControl; 505*f24741d9SOmair Javaid m_hbr_regs[hw_idx].address = tempAddr; 506*f24741d9SOmair Javaid m_hbr_regs[hw_idx].refcount = tempRefCount; 507*f24741d9SOmair Javaid 5083a56363aSOmair Javaid return false; 509*f24741d9SOmair Javaid } 5103a56363aSOmair Javaid 5113a56363aSOmair Javaid return true; 512ea8c25a8SOmair Javaid } 513ea8c25a8SOmair Javaid 514ea8c25a8SOmair Javaid return false; 515ea8c25a8SOmair Javaid } 516ea8c25a8SOmair Javaid 517ea8c25a8SOmair Javaid uint32_t 518ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints () 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 5253a56363aSOmair Javaid Error error; 5263a56363aSOmair Javaid 5271fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 5283a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 5293a56363aSOmair Javaid 5303a56363aSOmair Javaid if (error.Fail()) 5313a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 5321fd2a8cfSOmair Javaid 533ea8c25a8SOmair Javaid return m_max_hwp_supported; 534ea8c25a8SOmair Javaid } 535ea8c25a8SOmair Javaid 536ea8c25a8SOmair Javaid uint32_t 537ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) 538ea8c25a8SOmair Javaid { 539ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 540ea8c25a8SOmair Javaid 541ea8c25a8SOmair Javaid if (log) 542ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 543ea8c25a8SOmair Javaid 5443a56363aSOmair Javaid Error error; 545ea8c25a8SOmair Javaid 5463a56363aSOmair Javaid // Read hardware breakpoint and watchpoint information. 5473a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 5483a56363aSOmair Javaid 5493a56363aSOmair Javaid if (error.Fail()) 5503a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 5513a56363aSOmair Javaid 5523a56363aSOmair Javaid uint32_t control_value = 0, wp_index = 0; 553ea8c25a8SOmair Javaid 5541fd2a8cfSOmair Javaid // Check if we are setting watchpoint other than read/write/access 5551fd2a8cfSOmair Javaid // Also update watchpoint flag to match AArch64 write-read bit configuration. 5561fd2a8cfSOmair Javaid switch (watch_flags) 5571fd2a8cfSOmair Javaid { 5581fd2a8cfSOmair Javaid case 1: 5591fd2a8cfSOmair Javaid watch_flags = 2; 5601fd2a8cfSOmair Javaid break; 5611fd2a8cfSOmair Javaid case 2: 5621fd2a8cfSOmair Javaid watch_flags = 1; 5631fd2a8cfSOmair Javaid break; 5641fd2a8cfSOmair Javaid case 3: 5651fd2a8cfSOmair Javaid break; 5661fd2a8cfSOmair Javaid default: 5671fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 5681fd2a8cfSOmair Javaid } 569ea8c25a8SOmair Javaid 570ea8c25a8SOmair Javaid // Check if size has a valid hardware watchpoint length. 571ea8c25a8SOmair Javaid if (size != 1 && size != 2 && size != 4 && size != 8) 5721fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 573ea8c25a8SOmair Javaid 574ea8c25a8SOmair Javaid // Check 8-byte alignment for hardware watchpoint target address. 575ea8c25a8SOmair Javaid // TODO: Add support for watching un-aligned addresses 576ea8c25a8SOmair Javaid if (addr & 0x07) 5771fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 578ea8c25a8SOmair Javaid 579ea8c25a8SOmair Javaid // Setup control value 580ea8c25a8SOmair Javaid control_value = watch_flags << 3; 581ea8c25a8SOmair Javaid control_value |= ((1 << size) - 1) << 5; 582ea8c25a8SOmair Javaid control_value |= (2 << 1) | 1; 583ea8c25a8SOmair Javaid 584ea8c25a8SOmair Javaid // Iterate over stored watchpoints 585ea8c25a8SOmair Javaid // Find a free wp_index or update reference count if duplicate. 586ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 587ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 588ea8c25a8SOmair Javaid { 589ea8c25a8SOmair Javaid if ((m_hwp_regs[i].control & 1) == 0) 590ea8c25a8SOmair Javaid { 591ea8c25a8SOmair Javaid wp_index = i; // Mark last free slot 592ea8c25a8SOmair Javaid } 593ea8c25a8SOmair Javaid else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value) 594ea8c25a8SOmair Javaid { 595ea8c25a8SOmair Javaid wp_index = i; // Mark duplicate index 596ea8c25a8SOmair Javaid break; // Stop searching here 597ea8c25a8SOmair Javaid } 598ea8c25a8SOmair Javaid } 599ea8c25a8SOmair Javaid 600ea8c25a8SOmair Javaid if (wp_index == LLDB_INVALID_INDEX32) 601ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; 602ea8c25a8SOmair Javaid 603ea8c25a8SOmair Javaid // Add new or update existing watchpoint 604ea8c25a8SOmair Javaid if ((m_hwp_regs[wp_index].control & 1) == 0) 605ea8c25a8SOmair Javaid { 6061fd2a8cfSOmair Javaid // Update watchpoint in local cache 607ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = addr; 608ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control = control_value; 609ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount = 1; 610ea8c25a8SOmair Javaid 611ea8c25a8SOmair Javaid // PTRACE call to set corresponding watchpoint register. 6123a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 6133a56363aSOmair Javaid 6143a56363aSOmair Javaid if (error.Fail()) 615*f24741d9SOmair Javaid { 616*f24741d9SOmair Javaid m_hwp_regs[wp_index].address = 0; 617*f24741d9SOmair Javaid m_hwp_regs[wp_index].control &= ~1; 618*f24741d9SOmair Javaid m_hwp_regs[wp_index].refcount = 0; 619*f24741d9SOmair Javaid 6203a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 621ea8c25a8SOmair Javaid } 622*f24741d9SOmair Javaid } 623ea8c25a8SOmair Javaid else 624ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount++; 625ea8c25a8SOmair Javaid 626ea8c25a8SOmair Javaid return wp_index; 627ea8c25a8SOmair Javaid } 628ea8c25a8SOmair Javaid 629ea8c25a8SOmair Javaid bool 630ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index) 631ea8c25a8SOmair Javaid { 632ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 633ea8c25a8SOmair Javaid 634ea8c25a8SOmair Javaid if (log) 635ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 636ea8c25a8SOmair Javaid 6373a56363aSOmair Javaid Error error; 6383a56363aSOmair Javaid 6391fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 6403a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 6413a56363aSOmair Javaid 6423a56363aSOmair Javaid if (error.Fail()) 6433a56363aSOmair Javaid return false; 644ea8c25a8SOmair Javaid 645ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 646ea8c25a8SOmair Javaid return false; 647ea8c25a8SOmair Javaid 648ea8c25a8SOmair Javaid // Update reference count if multiple references. 649ea8c25a8SOmair Javaid if (m_hwp_regs[wp_index].refcount > 1) 650ea8c25a8SOmair Javaid { 651ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount--; 652ea8c25a8SOmair Javaid return true; 653ea8c25a8SOmair Javaid } 654ea8c25a8SOmair Javaid else if (m_hwp_regs[wp_index].refcount == 1) 655ea8c25a8SOmair Javaid { 656*f24741d9SOmair Javaid // Create a backup we can revert to in case of failure. 657*f24741d9SOmair Javaid lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 658*f24741d9SOmair Javaid uint32_t tempControl = m_hwp_regs[wp_index].control; 659*f24741d9SOmair Javaid uint32_t tempRefCount = m_hwp_regs[wp_index].refcount; 660*f24741d9SOmair Javaid 6611fd2a8cfSOmair Javaid // Update watchpoint in local cache 662ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control &= ~1; 663ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = 0; 664ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount = 0; 665ea8c25a8SOmair Javaid 6661fd2a8cfSOmair Javaid // Ptrace call to update hardware debug registers 6673a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 6683a56363aSOmair Javaid 6693a56363aSOmair Javaid if (error.Fail()) 670*f24741d9SOmair Javaid { 671*f24741d9SOmair Javaid m_hwp_regs[wp_index].control = tempControl; 672*f24741d9SOmair Javaid m_hwp_regs[wp_index].address = tempAddr; 673*f24741d9SOmair Javaid m_hwp_regs[wp_index].refcount = tempRefCount; 674*f24741d9SOmair Javaid 6753a56363aSOmair Javaid return false; 676*f24741d9SOmair Javaid } 6773a56363aSOmair Javaid 678ea8c25a8SOmair Javaid return true; 679ea8c25a8SOmair Javaid } 680ea8c25a8SOmair Javaid 681ea8c25a8SOmair Javaid return false; 682ea8c25a8SOmair Javaid } 683ea8c25a8SOmair Javaid 684ea8c25a8SOmair Javaid Error 685ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints () 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 6923a56363aSOmair Javaid Error error; 6933a56363aSOmair Javaid 6941fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 6953a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 6963a56363aSOmair Javaid 6973a56363aSOmair Javaid if (error.Fail()) 6983a56363aSOmair Javaid return error; 699ea8c25a8SOmair Javaid 700*f24741d9SOmair Javaid lldb::addr_t tempAddr = 0; 701*f24741d9SOmair Javaid uint32_t tempControl = 0, tempRefCount = 0; 702*f24741d9SOmair Javaid 703ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 704ea8c25a8SOmair Javaid { 705ea8c25a8SOmair Javaid if (m_hwp_regs[i].control & 0x01) 706ea8c25a8SOmair Javaid { 707*f24741d9SOmair Javaid // Create a backup we can revert to in case of failure. 708*f24741d9SOmair Javaid tempAddr = m_hwp_regs[i].address; 709*f24741d9SOmair Javaid tempControl = m_hwp_regs[i].control; 710*f24741d9SOmair Javaid tempRefCount = m_hwp_regs[i].refcount; 711*f24741d9SOmair Javaid 7121fd2a8cfSOmair Javaid // Clear watchpoints in local cache 713ea8c25a8SOmair Javaid m_hwp_regs[i].control &= ~1; 714ea8c25a8SOmair Javaid m_hwp_regs[i].address = 0; 715ea8c25a8SOmair Javaid m_hwp_regs[i].refcount = 0; 716ea8c25a8SOmair Javaid 7171fd2a8cfSOmair Javaid // Ptrace call to update hardware debug registers 7183a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 7193a56363aSOmair Javaid 7203a56363aSOmair Javaid if (error.Fail()) 721*f24741d9SOmair Javaid { 722*f24741d9SOmair Javaid m_hwp_regs[i].control = tempControl; 723*f24741d9SOmair Javaid m_hwp_regs[i].address = tempAddr; 724*f24741d9SOmair Javaid m_hwp_regs[i].refcount = tempRefCount; 725*f24741d9SOmair Javaid 7263a56363aSOmair Javaid return error; 727ea8c25a8SOmair Javaid } 728ea8c25a8SOmair Javaid } 729*f24741d9SOmair Javaid } 730ea8c25a8SOmair Javaid 731ea8c25a8SOmair Javaid return Error(); 732ea8c25a8SOmair Javaid } 733ea8c25a8SOmair Javaid 734ea8c25a8SOmair Javaid uint32_t 735ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) 736ea8c25a8SOmair Javaid { 737ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 738ea8c25a8SOmair Javaid 739ea8c25a8SOmair Javaid if (log) 740ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 741ea8c25a8SOmair Javaid switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) 742ea8c25a8SOmair Javaid { 743ea8c25a8SOmair Javaid case 0x01: 744ea8c25a8SOmair Javaid return 1; 745ea8c25a8SOmair Javaid case 0x03: 746ea8c25a8SOmair Javaid return 2; 747ea8c25a8SOmair Javaid case 0x0f: 748ea8c25a8SOmair Javaid return 4; 749ea8c25a8SOmair Javaid case 0xff: 750ea8c25a8SOmair Javaid return 8; 751ea8c25a8SOmair Javaid default: 752ea8c25a8SOmair Javaid return 0; 753ea8c25a8SOmair Javaid } 754ea8c25a8SOmair Javaid } 755ea8c25a8SOmair Javaid bool 756ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) 757ea8c25a8SOmair Javaid { 758ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 759ea8c25a8SOmair Javaid 760ea8c25a8SOmair Javaid if (log) 761ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 762ea8c25a8SOmair Javaid 763ea8c25a8SOmair Javaid if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 764ea8c25a8SOmair Javaid return true; 765ea8c25a8SOmair Javaid else 766ea8c25a8SOmair Javaid return false; 767ea8c25a8SOmair Javaid } 768ea8c25a8SOmair Javaid 769ea8c25a8SOmair Javaid Error 770ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) 771ea8c25a8SOmair Javaid { 772ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 773ea8c25a8SOmair Javaid 774ea8c25a8SOmair Javaid if (log) 775ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 776ea8c25a8SOmair Javaid 777ea8c25a8SOmair Javaid uint32_t watch_size; 778ea8c25a8SOmair Javaid lldb::addr_t watch_addr; 779ea8c25a8SOmair Javaid 780ea8c25a8SOmair Javaid for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) 781ea8c25a8SOmair Javaid { 782ea8c25a8SOmair Javaid watch_size = GetWatchpointSize (wp_index); 783ea8c25a8SOmair Javaid watch_addr = m_hwp_regs[wp_index].address; 784ea8c25a8SOmair Javaid 785ea8c25a8SOmair Javaid if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) 786ea8c25a8SOmair Javaid && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) 787ea8c25a8SOmair Javaid { 788ea8c25a8SOmair Javaid return Error(); 789ea8c25a8SOmair Javaid } 790ea8c25a8SOmair Javaid } 791ea8c25a8SOmair Javaid 792ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 793ea8c25a8SOmair Javaid return Error(); 794ea8c25a8SOmair Javaid } 795ea8c25a8SOmair Javaid 796ea8c25a8SOmair Javaid lldb::addr_t 797ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index) 798ea8c25a8SOmair Javaid { 799ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 800ea8c25a8SOmair Javaid 801ea8c25a8SOmair Javaid if (log) 802ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 803ea8c25a8SOmair Javaid 804ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 805ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 806ea8c25a8SOmair Javaid 807ea8c25a8SOmair Javaid if (WatchpointIsEnabled(wp_index)) 808ea8c25a8SOmair Javaid return m_hwp_regs[wp_index].address; 809ea8c25a8SOmair Javaid else 810ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 811ea8c25a8SOmair Javaid } 812ea8c25a8SOmair Javaid 813068f8a7eSTamas Berghammer Error 8141fd2a8cfSOmair Javaid NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() 815ea8c25a8SOmair Javaid { 8161fd2a8cfSOmair Javaid if (!m_refresh_hwdebug_info) 8171fd2a8cfSOmair Javaid { 8181fd2a8cfSOmair Javaid return Error(); 8191fd2a8cfSOmair Javaid } 8201fd2a8cfSOmair Javaid 821c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 822ea8c25a8SOmair Javaid 823c7512fdcSPavel Labath int regset = NT_ARM_HW_WATCH; 824c7512fdcSPavel Labath struct iovec ioVec; 825c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 826c7512fdcSPavel Labath Error error; 827c7512fdcSPavel Labath 828c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 829c7512fdcSPavel Labath ioVec.iov_len = sizeof (dreg_state); 8304a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 8313a56363aSOmair Javaid 8323a56363aSOmair Javaid if (error.Fail()) 8333a56363aSOmair Javaid return error; 8343a56363aSOmair Javaid 8351fd2a8cfSOmair Javaid m_max_hwp_supported = dreg_state.dbg_info & 0xff; 836c7512fdcSPavel Labath 837c7512fdcSPavel Labath regset = NT_ARM_HW_BREAK; 8384a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 8391fd2a8cfSOmair Javaid 8403a56363aSOmair Javaid if (error.Fail()) 8413a56363aSOmair Javaid return error; 8423a56363aSOmair Javaid 8433a56363aSOmair Javaid m_max_hbp_supported = dreg_state.dbg_info & 0xff; 8441fd2a8cfSOmair Javaid m_refresh_hwdebug_info = false; 845c7512fdcSPavel Labath 846c7512fdcSPavel Labath return error; 847ea8c25a8SOmair Javaid } 848068f8a7eSTamas Berghammer 849068f8a7eSTamas Berghammer Error 8501fd2a8cfSOmair Javaid NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) 851068f8a7eSTamas Berghammer { 852c7512fdcSPavel Labath struct iovec ioVec; 853c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 854c7512fdcSPavel Labath Error error; 855c7512fdcSPavel Labath 856c7512fdcSPavel Labath memset (&dreg_state, 0, sizeof (dreg_state)); 857c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 858c7512fdcSPavel Labath 8591fd2a8cfSOmair Javaid if (hwbType == eDREGTypeWATCH) 860c7512fdcSPavel Labath { 8611fd2a8cfSOmair Javaid hwbType = NT_ARM_HW_WATCH; 8625cf948d2SOmair Javaid ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad) 8635cf948d2SOmair Javaid + (sizeof (dreg_state.dbg_regs [0]) * m_max_hwp_supported); 8641fd2a8cfSOmair Javaid 8651fd2a8cfSOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 8661fd2a8cfSOmair Javaid { 8671fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; 8681fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; 8691fd2a8cfSOmair Javaid } 8701fd2a8cfSOmair Javaid } 8711fd2a8cfSOmair Javaid else 8721fd2a8cfSOmair Javaid { 8731fd2a8cfSOmair Javaid hwbType = NT_ARM_HW_BREAK; 8745cf948d2SOmair Javaid ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad) 8755cf948d2SOmair Javaid + (sizeof (dreg_state.dbg_regs [0]) * m_max_hbp_supported); 8761fd2a8cfSOmair Javaid 8771fd2a8cfSOmair Javaid for (uint32_t i = 0; i < m_max_hbp_supported; i++) 8781fd2a8cfSOmair Javaid { 8791fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address; 8801fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control; 8811fd2a8cfSOmair Javaid } 882068f8a7eSTamas Berghammer } 883068f8a7eSTamas Berghammer 8841fd2a8cfSOmair Javaid return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &hwbType, &ioVec, ioVec.iov_len); 885c7512fdcSPavel Labath } 886c7512fdcSPavel Labath 887c7512fdcSPavel Labath Error 888c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset, 889068f8a7eSTamas Berghammer const char* reg_name, 890068f8a7eSTamas Berghammer uint32_t size, 891068f8a7eSTamas Berghammer RegisterValue &value) 892068f8a7eSTamas Berghammer { 893c7512fdcSPavel Labath Error error; 894c7512fdcSPavel Labath if (offset > sizeof(struct user_pt_regs)) 895c7512fdcSPavel Labath { 896c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 897c7512fdcSPavel Labath if (offset > sizeof(struct user_fpsimd_state)) 898c7512fdcSPavel Labath { 899c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 900c7512fdcSPavel Labath return error; 901c7512fdcSPavel Labath } 902c7512fdcSPavel Labath elf_fpregset_t regs; 903c7512fdcSPavel Labath int regset = NT_FPREGSET; 904c7512fdcSPavel Labath struct iovec ioVec; 905c7512fdcSPavel Labath 906c7512fdcSPavel Labath ioVec.iov_base = ®s; 907c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 9084a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 9094a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 910c7512fdcSPavel Labath if (error.Success()) 911c7512fdcSPavel Labath { 912c7512fdcSPavel Labath ArchSpec arch; 913c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 914c7512fdcSPavel Labath value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, arch.GetByteOrder()); 915c7512fdcSPavel Labath else 916c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 917c7512fdcSPavel Labath } 918c7512fdcSPavel Labath } 919c7512fdcSPavel Labath else 920c7512fdcSPavel Labath { 921c7512fdcSPavel Labath elf_gregset_t regs; 922c7512fdcSPavel Labath int regset = NT_PRSTATUS; 923c7512fdcSPavel Labath struct iovec ioVec; 924c7512fdcSPavel Labath 925c7512fdcSPavel Labath ioVec.iov_base = ®s; 926c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 9274a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 9284a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 929c7512fdcSPavel Labath if (error.Success()) 930c7512fdcSPavel Labath { 931c7512fdcSPavel Labath ArchSpec arch; 932c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 933c7512fdcSPavel Labath value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder()); 934c7512fdcSPavel Labath else 935c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 936c7512fdcSPavel Labath } 937c7512fdcSPavel Labath } 938c7512fdcSPavel Labath return error; 939068f8a7eSTamas Berghammer } 940068f8a7eSTamas Berghammer 941c7512fdcSPavel Labath Error 942c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset, 943068f8a7eSTamas Berghammer const char* reg_name, 944068f8a7eSTamas Berghammer const RegisterValue &value) 945068f8a7eSTamas Berghammer { 946c7512fdcSPavel Labath Error error; 947c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 948c7512fdcSPavel Labath if (offset > sizeof(struct user_pt_regs)) 949c7512fdcSPavel Labath { 950c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 951c7512fdcSPavel Labath if (offset > sizeof(struct user_fpsimd_state)) 952c7512fdcSPavel Labath { 953c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 954c7512fdcSPavel Labath return error; 955c7512fdcSPavel Labath } 956c7512fdcSPavel Labath elf_fpregset_t regs; 957c7512fdcSPavel Labath int regset = NT_FPREGSET; 958c7512fdcSPavel Labath struct iovec ioVec; 959c7512fdcSPavel Labath 960c7512fdcSPavel Labath ioVec.iov_base = ®s; 961c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 9624a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 963c7512fdcSPavel Labath 964c7512fdcSPavel Labath if (error.Success()) 965c7512fdcSPavel Labath { 966c7512fdcSPavel Labath ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 16); 9674a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 968c7512fdcSPavel Labath } 969c7512fdcSPavel Labath } 970c7512fdcSPavel Labath else 971c7512fdcSPavel Labath { 972c7512fdcSPavel Labath elf_gregset_t regs; 973c7512fdcSPavel Labath int regset = NT_PRSTATUS; 974c7512fdcSPavel Labath struct iovec ioVec; 975c7512fdcSPavel Labath 976c7512fdcSPavel Labath ioVec.iov_base = ®s; 977c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 9784a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 979c7512fdcSPavel Labath if (error.Success()) 980c7512fdcSPavel Labath { 981c7512fdcSPavel Labath ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 8); 9824a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 983c7512fdcSPavel Labath } 984c7512fdcSPavel Labath } 985c7512fdcSPavel Labath return error; 986068f8a7eSTamas Berghammer } 987068f8a7eSTamas Berghammer 988c7512fdcSPavel Labath Error 989c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) 990068f8a7eSTamas Berghammer { 991c7512fdcSPavel Labath int regset = NT_PRSTATUS; 992c7512fdcSPavel Labath struct iovec ioVec; 993c7512fdcSPavel Labath Error error; 994c7512fdcSPavel Labath 995c7512fdcSPavel Labath ioVec.iov_base = buf; 996c7512fdcSPavel Labath ioVec.iov_len = buf_size; 9974a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 998068f8a7eSTamas Berghammer } 999068f8a7eSTamas Berghammer 1000c7512fdcSPavel Labath Error 1001c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) 1002068f8a7eSTamas Berghammer { 1003c7512fdcSPavel Labath int regset = NT_PRSTATUS; 1004c7512fdcSPavel Labath struct iovec ioVec; 1005c7512fdcSPavel Labath Error error; 1006c7512fdcSPavel Labath 1007c7512fdcSPavel Labath ioVec.iov_base = buf; 1008c7512fdcSPavel Labath ioVec.iov_len = buf_size; 10094a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1010068f8a7eSTamas Berghammer } 1011068f8a7eSTamas Berghammer 1012c7512fdcSPavel Labath Error 1013c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) 1014068f8a7eSTamas Berghammer { 1015c7512fdcSPavel Labath int regset = NT_FPREGSET; 1016c7512fdcSPavel Labath struct iovec ioVec; 1017c7512fdcSPavel Labath Error error; 1018c7512fdcSPavel Labath 1019c7512fdcSPavel Labath ioVec.iov_base = buf; 1020c7512fdcSPavel Labath ioVec.iov_len = buf_size; 10214a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1022068f8a7eSTamas Berghammer } 1023068f8a7eSTamas Berghammer 1024c7512fdcSPavel Labath Error 1025c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) 1026068f8a7eSTamas Berghammer { 1027c7512fdcSPavel Labath int regset = NT_FPREGSET; 1028c7512fdcSPavel Labath struct iovec ioVec; 1029c7512fdcSPavel Labath Error error; 1030c7512fdcSPavel Labath 1031c7512fdcSPavel Labath ioVec.iov_base = buf; 1032c7512fdcSPavel Labath ioVec.iov_len = buf_size; 10334a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1034068f8a7eSTamas Berghammer } 1035068f8a7eSTamas Berghammer 1036c40e7b17STamas Berghammer uint32_t 1037c40e7b17STamas Berghammer NativeRegisterContextLinux_arm64::CalculateFprOffset(const RegisterInfo* reg_info) const 1038c40e7b17STamas Berghammer { 1039c40e7b17STamas Berghammer return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; 1040c40e7b17STamas Berghammer } 1041c40e7b17STamas Berghammer 1042068f8a7eSTamas Berghammer #endif // defined (__arm64__) || defined (__aarch64__) 1043