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 12e85e6021STamas Berghammer #include "NativeRegisterContextLinux_arm.h" 131e209fccSTamas Berghammer #include "NativeRegisterContextLinux_arm64.h" 141e209fccSTamas Berghammer 15068f8a7eSTamas Berghammer // C Includes 16068f8a7eSTamas Berghammer // C++ Includes 17068f8a7eSTamas Berghammer 18068f8a7eSTamas Berghammer // Other libraries and framework includes 191e209fccSTamas Berghammer #include "lldb/Core/DataBufferHeap.h" 201e209fccSTamas Berghammer #include "lldb/Core/Error.h" 21068f8a7eSTamas Berghammer #include "lldb/Core/Log.h" 221e209fccSTamas Berghammer #include "lldb/Core/RegisterValue.h" 231e209fccSTamas Berghammer #include "lldb/Host/common/NativeProcessProtocol.h" 241e209fccSTamas Berghammer 25068f8a7eSTamas Berghammer #include "Plugins/Process/Linux/NativeProcessLinux.h" 26068f8a7eSTamas Berghammer #include "Plugins/Process/Linux/Procfs.h" 27e85e6021STamas Berghammer #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 28068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" 29068f8a7eSTamas Berghammer 30*b9c1b51eSKate Stone // System includes - They have to be included after framework includes because 31*b9c1b51eSKate Stone // they define some 32068f8a7eSTamas Berghammer // macros which collide with variable names in other modules 33068f8a7eSTamas Berghammer #include <sys/socket.h> 34068f8a7eSTamas Berghammer // NT_PRSTATUS and NT_FPREGSET definition 35068f8a7eSTamas Berghammer #include <elf.h> 36dd4799c2SSaleem Abdulrasool // user_hwdebug_state definition 37dd4799c2SSaleem Abdulrasool #include <asm/ptrace.h> 38068f8a7eSTamas Berghammer 39068f8a7eSTamas Berghammer #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) 401e209fccSTamas Berghammer 411e209fccSTamas Berghammer using namespace lldb; 421e209fccSTamas Berghammer using namespace lldb_private; 43db264a6dSTamas Berghammer using namespace lldb_private::process_linux; 441e209fccSTamas Berghammer 451e209fccSTamas Berghammer // ARM64 general purpose registers. 46*b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_arm64[] = { 47*b9c1b51eSKate Stone gpr_x0_arm64, gpr_x1_arm64, gpr_x2_arm64, gpr_x3_arm64, 48*b9c1b51eSKate Stone gpr_x4_arm64, gpr_x5_arm64, gpr_x6_arm64, gpr_x7_arm64, 49*b9c1b51eSKate Stone gpr_x8_arm64, gpr_x9_arm64, gpr_x10_arm64, gpr_x11_arm64, 50*b9c1b51eSKate Stone gpr_x12_arm64, gpr_x13_arm64, gpr_x14_arm64, gpr_x15_arm64, 51*b9c1b51eSKate Stone gpr_x16_arm64, gpr_x17_arm64, gpr_x18_arm64, gpr_x19_arm64, 52*b9c1b51eSKate Stone gpr_x20_arm64, gpr_x21_arm64, gpr_x22_arm64, gpr_x23_arm64, 53*b9c1b51eSKate Stone gpr_x24_arm64, gpr_x25_arm64, gpr_x26_arm64, gpr_x27_arm64, 54*b9c1b51eSKate Stone gpr_x28_arm64, gpr_fp_arm64, gpr_lr_arm64, gpr_sp_arm64, 55*b9c1b51eSKate Stone gpr_pc_arm64, gpr_cpsr_arm64, 561e209fccSTamas Berghammer LLDB_INVALID_REGNUM // register sets need to end with this flag 571e209fccSTamas Berghammer }; 58*b9c1b51eSKate Stone static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 59*b9c1b51eSKate Stone 1) == k_num_gpr_registers_arm64, 601e209fccSTamas Berghammer "g_gpr_regnums_arm64 has wrong number of register infos"); 611e209fccSTamas Berghammer 621e209fccSTamas Berghammer // ARM64 floating point registers. 63*b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_arm64[] = { 64*b9c1b51eSKate Stone fpu_v0_arm64, fpu_v1_arm64, fpu_v2_arm64, fpu_v3_arm64, 65*b9c1b51eSKate Stone fpu_v4_arm64, fpu_v5_arm64, fpu_v6_arm64, fpu_v7_arm64, 66*b9c1b51eSKate Stone fpu_v8_arm64, fpu_v9_arm64, fpu_v10_arm64, fpu_v11_arm64, 67*b9c1b51eSKate Stone fpu_v12_arm64, fpu_v13_arm64, fpu_v14_arm64, fpu_v15_arm64, 68*b9c1b51eSKate Stone fpu_v16_arm64, fpu_v17_arm64, fpu_v18_arm64, fpu_v19_arm64, 69*b9c1b51eSKate Stone fpu_v20_arm64, fpu_v21_arm64, fpu_v22_arm64, fpu_v23_arm64, 70*b9c1b51eSKate Stone fpu_v24_arm64, fpu_v25_arm64, fpu_v26_arm64, fpu_v27_arm64, 71*b9c1b51eSKate Stone fpu_v28_arm64, fpu_v29_arm64, fpu_v30_arm64, fpu_v31_arm64, 72*b9c1b51eSKate Stone fpu_fpsr_arm64, fpu_fpcr_arm64, 731e209fccSTamas Berghammer LLDB_INVALID_REGNUM // register sets need to end with this flag 741e209fccSTamas Berghammer }; 75*b9c1b51eSKate Stone static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 76*b9c1b51eSKate Stone 1) == k_num_fpr_registers_arm64, 771e209fccSTamas Berghammer "g_fpu_regnums_arm64 has wrong number of register infos"); 781e209fccSTamas Berghammer 791e209fccSTamas Berghammer namespace { 801e209fccSTamas Berghammer // Number of register sets provided by this context. 81*b9c1b51eSKate Stone enum { k_num_register_sets = 2 }; 821e209fccSTamas Berghammer } 831e209fccSTamas Berghammer 841e209fccSTamas Berghammer // Register sets for ARM64. 85*b9c1b51eSKate Stone static const RegisterSet g_reg_sets_arm64[k_num_register_sets] = { 86*b9c1b51eSKate Stone {"General Purpose Registers", "gpr", k_num_gpr_registers_arm64, 87*b9c1b51eSKate Stone g_gpr_regnums_arm64}, 88*b9c1b51eSKate Stone {"Floating Point Registers", "fpu", k_num_fpr_registers_arm64, 89*b9c1b51eSKate Stone g_fpu_regnums_arm64}}; 901e209fccSTamas Berghammer 91068f8a7eSTamas Berghammer NativeRegisterContextLinux * 92*b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 93*b9c1b51eSKate Stone const ArchSpec &target_arch, NativeThreadProtocol &native_thread, 94*b9c1b51eSKate Stone uint32_t concrete_frame_idx) { 95e85e6021STamas Berghammer Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS); 96*b9c1b51eSKate Stone switch (target_arch.GetMachine()) { 97e85e6021STamas Berghammer case llvm::Triple::arm: 98*b9c1b51eSKate Stone return new NativeRegisterContextLinux_arm(target_arch, native_thread, 99*b9c1b51eSKate Stone concrete_frame_idx); 100e85e6021STamas Berghammer case llvm::Triple::aarch64: 101*b9c1b51eSKate Stone return new NativeRegisterContextLinux_arm64(target_arch, native_thread, 102*b9c1b51eSKate Stone concrete_frame_idx); 103e85e6021STamas Berghammer default: 104e85e6021STamas Berghammer if (log) 105*b9c1b51eSKate Stone log->Printf("NativeRegisterContextLinux::%s() have no register context " 106*b9c1b51eSKate Stone "for architecture: %s\n", 107*b9c1b51eSKate Stone __FUNCTION__, 108e85e6021STamas Berghammer target_arch.GetTriple().getArchName().str().c_str()); 109e85e6021STamas Berghammer return nullptr; 110e85e6021STamas Berghammer } 111068f8a7eSTamas Berghammer } 112068f8a7eSTamas Berghammer 113*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64( 114*b9c1b51eSKate Stone const ArchSpec &target_arch, NativeThreadProtocol &native_thread, 115*b9c1b51eSKate Stone uint32_t concrete_frame_idx) 116*b9c1b51eSKate Stone : NativeRegisterContextLinux(native_thread, concrete_frame_idx, 117*b9c1b51eSKate Stone new RegisterContextLinux_arm64(target_arch)) { 118*b9c1b51eSKate Stone switch (target_arch.GetMachine()) { 1191e209fccSTamas Berghammer case llvm::Triple::aarch64: 1201e209fccSTamas Berghammer m_reg_info.num_registers = k_num_registers_arm64; 1211e209fccSTamas Berghammer m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64; 1221e209fccSTamas Berghammer m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64; 1231e209fccSTamas Berghammer m_reg_info.last_gpr = k_last_gpr_arm64; 1241e209fccSTamas Berghammer m_reg_info.first_fpr = k_first_fpr_arm64; 1251e209fccSTamas Berghammer m_reg_info.last_fpr = k_last_fpr_arm64; 1261e209fccSTamas Berghammer m_reg_info.first_fpr_v = fpu_v0_arm64; 1271e209fccSTamas Berghammer m_reg_info.last_fpr_v = fpu_v31_arm64; 1281e209fccSTamas Berghammer m_reg_info.gpr_flags = gpr_cpsr_arm64; 1291e209fccSTamas Berghammer break; 1301e209fccSTamas Berghammer default: 1311e209fccSTamas Berghammer assert(false && "Unhandled target architecture."); 1321e209fccSTamas Berghammer break; 1331e209fccSTamas Berghammer } 1341e209fccSTamas Berghammer 1351e209fccSTamas Berghammer ::memset(&m_fpr, 0, sizeof(m_fpr)); 1361e209fccSTamas Berghammer ::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64)); 137ea8c25a8SOmair Javaid ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); 138ea8c25a8SOmair Javaid 139ea8c25a8SOmair Javaid // 16 is just a maximum value, query hardware for actual watchpoint count 140ea8c25a8SOmair Javaid m_max_hwp_supported = 16; 141ea8c25a8SOmair Javaid m_max_hbp_supported = 16; 142ea8c25a8SOmair Javaid m_refresh_hwdebug_info = true; 1431e209fccSTamas Berghammer } 1441e209fccSTamas Berghammer 145*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::GetRegisterSetCount() const { 1461e209fccSTamas Berghammer return k_num_register_sets; 1471e209fccSTamas Berghammer } 1481e209fccSTamas Berghammer 149db264a6dSTamas Berghammer const RegisterSet * 150*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetRegisterSet(uint32_t set_index) const { 1511e209fccSTamas Berghammer if (set_index < k_num_register_sets) 1521e209fccSTamas Berghammer return &g_reg_sets_arm64[set_index]; 1531e209fccSTamas Berghammer 1541e209fccSTamas Berghammer return nullptr; 1551e209fccSTamas Berghammer } 1561e209fccSTamas Berghammer 157*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::GetUserRegisterCount() const { 158cec93c35STamas Berghammer uint32_t count = 0; 159cec93c35STamas Berghammer for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) 160cec93c35STamas Berghammer count += g_reg_sets_arm64[set_index].num_registers; 161cec93c35STamas Berghammer return count; 162cec93c35STamas Berghammer } 163cec93c35STamas Berghammer 164*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadRegister( 165*b9c1b51eSKate Stone const RegisterInfo *reg_info, RegisterValue ®_value) { 1661e209fccSTamas Berghammer Error error; 1671e209fccSTamas Berghammer 168*b9c1b51eSKate Stone if (!reg_info) { 1691e209fccSTamas Berghammer error.SetErrorString("reg_info NULL"); 1701e209fccSTamas Berghammer return error; 1711e209fccSTamas Berghammer } 1721e209fccSTamas Berghammer 1731e209fccSTamas Berghammer const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 1741e209fccSTamas Berghammer 175*b9c1b51eSKate Stone if (IsFPR(reg)) { 176068f8a7eSTamas Berghammer error = ReadFPR(); 177068f8a7eSTamas Berghammer if (error.Fail()) 1781e209fccSTamas Berghammer return error; 179*b9c1b51eSKate Stone } else { 1801e209fccSTamas Berghammer uint32_t full_reg = reg; 181*b9c1b51eSKate Stone bool is_subreg = reg_info->invalidate_regs && 182*b9c1b51eSKate Stone (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 1831e209fccSTamas Berghammer 184*b9c1b51eSKate Stone if (is_subreg) { 1851e209fccSTamas Berghammer // Read the full aligned 64-bit register. 1861e209fccSTamas Berghammer full_reg = reg_info->invalidate_regs[0]; 1871e209fccSTamas Berghammer } 1881e209fccSTamas Berghammer 1891e209fccSTamas Berghammer error = ReadRegisterRaw(full_reg, reg_value); 1901e209fccSTamas Berghammer 191*b9c1b51eSKate Stone if (error.Success()) { 192*b9c1b51eSKate Stone // If our read was not aligned (for ah,bh,ch,dh), shift our returned value 193*b9c1b51eSKate Stone // one byte to the right. 1941e209fccSTamas Berghammer if (is_subreg && (reg_info->byte_offset & 0x1)) 1951e209fccSTamas Berghammer reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); 1961e209fccSTamas Berghammer 197*b9c1b51eSKate Stone // If our return byte size was greater than the return value reg size, 198*b9c1b51eSKate Stone // then 1991e209fccSTamas Berghammer // use the type specified by reg_info rather than the uint64_t default 2001e209fccSTamas Berghammer if (reg_value.GetByteSize() > reg_info->byte_size) 2011e209fccSTamas Berghammer reg_value.SetType(reg_info); 2021e209fccSTamas Berghammer } 2031e209fccSTamas Berghammer return error; 2041e209fccSTamas Berghammer } 2051e209fccSTamas Berghammer 2061e209fccSTamas Berghammer // Get pointer to m_fpr variable and set the data from it. 207c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 208c40e7b17STamas Berghammer assert(fpr_offset < sizeof m_fpr); 209c40e7b17STamas Berghammer uint8_t *src = (uint8_t *)&m_fpr + fpr_offset; 210*b9c1b51eSKate Stone reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, 211*b9c1b51eSKate Stone eByteOrderLittle, error); 2121e209fccSTamas Berghammer 2131e209fccSTamas Berghammer return error; 2141e209fccSTamas Berghammer } 2151e209fccSTamas Berghammer 216*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteRegister( 217*b9c1b51eSKate Stone const RegisterInfo *reg_info, const RegisterValue ®_value) { 2181e209fccSTamas Berghammer if (!reg_info) 2191e209fccSTamas Berghammer return Error("reg_info NULL"); 2201e209fccSTamas Berghammer 2211e209fccSTamas Berghammer const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 2221e209fccSTamas Berghammer if (reg_index == LLDB_INVALID_REGNUM) 223*b9c1b51eSKate Stone return Error("no lldb regnum for %s", reg_info && reg_info->name 224*b9c1b51eSKate Stone ? reg_info->name 225*b9c1b51eSKate Stone : "<unknown register>"); 2261e209fccSTamas Berghammer 2271e209fccSTamas Berghammer if (IsGPR(reg_index)) 2281e209fccSTamas Berghammer return WriteRegisterRaw(reg_index, reg_value); 2291e209fccSTamas Berghammer 230*b9c1b51eSKate Stone if (IsFPR(reg_index)) { 2311e209fccSTamas Berghammer // Get pointer to m_fpr variable and set the data to it. 232c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 233c40e7b17STamas Berghammer assert(fpr_offset < sizeof m_fpr); 234c40e7b17STamas Berghammer uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset; 235*b9c1b51eSKate Stone switch (reg_info->byte_size) { 2361e209fccSTamas Berghammer case 2: 2371e209fccSTamas Berghammer *(uint16_t *)dst = reg_value.GetAsUInt16(); 2381e209fccSTamas Berghammer break; 2391e209fccSTamas Berghammer case 4: 2401e209fccSTamas Berghammer *(uint32_t *)dst = reg_value.GetAsUInt32(); 2411e209fccSTamas Berghammer break; 2421e209fccSTamas Berghammer case 8: 2431e209fccSTamas Berghammer *(uint64_t *)dst = reg_value.GetAsUInt64(); 2441e209fccSTamas Berghammer break; 2451e209fccSTamas Berghammer default: 2461e209fccSTamas Berghammer assert(false && "Unhandled data size."); 247*b9c1b51eSKate Stone return Error("unhandled register data size %" PRIu32, 248*b9c1b51eSKate Stone reg_info->byte_size); 2491e209fccSTamas Berghammer } 2501e209fccSTamas Berghammer 251068f8a7eSTamas Berghammer Error error = WriteFPR(); 252068f8a7eSTamas Berghammer if (error.Fail()) 253068f8a7eSTamas Berghammer return error; 2541e209fccSTamas Berghammer 2551e209fccSTamas Berghammer return Error(); 2561e209fccSTamas Berghammer } 2571e209fccSTamas Berghammer 258*b9c1b51eSKate Stone return Error("failed - register wasn't recognized to be a GPR or an FPR, " 259*b9c1b51eSKate Stone "write strategy unknown"); 2601e209fccSTamas Berghammer } 2611e209fccSTamas Berghammer 262*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadAllRegisterValues( 263*b9c1b51eSKate Stone lldb::DataBufferSP &data_sp) { 2641e209fccSTamas Berghammer Error error; 2651e209fccSTamas Berghammer 266db264a6dSTamas Berghammer data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 2671e209fccSTamas Berghammer if (!data_sp) 268*b9c1b51eSKate Stone return Error("failed to allocate DataBufferHeap instance of size %" PRIu64, 269*b9c1b51eSKate Stone REG_CONTEXT_SIZE); 2701e209fccSTamas Berghammer 271068f8a7eSTamas Berghammer error = ReadGPR(); 272068f8a7eSTamas Berghammer if (error.Fail()) 2731e209fccSTamas Berghammer return error; 2741e209fccSTamas Berghammer 275068f8a7eSTamas Berghammer error = ReadFPR(); 276068f8a7eSTamas Berghammer if (error.Fail()) 2771e209fccSTamas Berghammer return error; 2781e209fccSTamas Berghammer 2791e209fccSTamas Berghammer uint8_t *dst = data_sp->GetBytes(); 280*b9c1b51eSKate Stone if (dst == nullptr) { 281*b9c1b51eSKate Stone error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 282*b9c1b51eSKate Stone " returned a null pointer", 283*b9c1b51eSKate Stone REG_CONTEXT_SIZE); 2841e209fccSTamas Berghammer return error; 2851e209fccSTamas Berghammer } 2861e209fccSTamas Berghammer 2871e209fccSTamas Berghammer ::memcpy(dst, &m_gpr_arm64, GetGPRSize()); 2881e209fccSTamas Berghammer dst += GetGPRSize(); 2891e209fccSTamas Berghammer ::memcpy(dst, &m_fpr, sizeof(m_fpr)); 2901e209fccSTamas Berghammer 2911e209fccSTamas Berghammer return error; 2921e209fccSTamas Berghammer } 2931e209fccSTamas Berghammer 294*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteAllRegisterValues( 295*b9c1b51eSKate Stone const lldb::DataBufferSP &data_sp) { 2961e209fccSTamas Berghammer Error error; 2971e209fccSTamas Berghammer 298*b9c1b51eSKate Stone if (!data_sp) { 299*b9c1b51eSKate Stone error.SetErrorStringWithFormat( 300*b9c1b51eSKate Stone "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", 301*b9c1b51eSKate Stone __FUNCTION__); 3021e209fccSTamas Berghammer return error; 3031e209fccSTamas Berghammer } 3041e209fccSTamas Berghammer 305*b9c1b51eSKate Stone if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 306*b9c1b51eSKate Stone error.SetErrorStringWithFormat( 307*b9c1b51eSKate Stone "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " 308*b9c1b51eSKate Stone "data size, expected %" PRIu64 ", actual %" PRIu64, 309*b9c1b51eSKate Stone __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 3101e209fccSTamas Berghammer return error; 3111e209fccSTamas Berghammer } 3121e209fccSTamas Berghammer 3131e209fccSTamas Berghammer uint8_t *src = data_sp->GetBytes(); 314*b9c1b51eSKate Stone if (src == nullptr) { 315*b9c1b51eSKate Stone error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " 316*b9c1b51eSKate Stone "DataBuffer::GetBytes() returned a null " 317*b9c1b51eSKate Stone "pointer", 318*b9c1b51eSKate Stone __FUNCTION__); 3191e209fccSTamas Berghammer return error; 3201e209fccSTamas Berghammer } 3211e209fccSTamas Berghammer ::memcpy(&m_gpr_arm64, src, GetRegisterInfoInterface().GetGPRSize()); 3221e209fccSTamas Berghammer 323068f8a7eSTamas Berghammer error = WriteGPR(); 324068f8a7eSTamas Berghammer if (error.Fail()) 3251e209fccSTamas Berghammer return error; 3261e209fccSTamas Berghammer 3271e209fccSTamas Berghammer src += GetRegisterInfoInterface().GetGPRSize(); 3281e209fccSTamas Berghammer ::memcpy(&m_fpr, src, sizeof(m_fpr)); 3291e209fccSTamas Berghammer 330068f8a7eSTamas Berghammer error = WriteFPR(); 3311e209fccSTamas Berghammer if (error.Fail()) 3321e209fccSTamas Berghammer return error; 3331e209fccSTamas Berghammer 3341e209fccSTamas Berghammer return error; 3351e209fccSTamas Berghammer } 3361e209fccSTamas Berghammer 337*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const { 3381e209fccSTamas Berghammer return reg <= m_reg_info.last_gpr; // GPR's come first. 3391e209fccSTamas Berghammer } 3401e209fccSTamas Berghammer 341*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const { 3421e209fccSTamas Berghammer return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 3431e209fccSTamas Berghammer } 3441e209fccSTamas Berghammer 345ea8c25a8SOmair Javaid uint32_t 346*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::SetHardwareBreakpoint(lldb::addr_t addr, 347*b9c1b51eSKate Stone size_t size) { 348ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 349ea8c25a8SOmair Javaid 350ea8c25a8SOmair Javaid if (log) 351ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 352ea8c25a8SOmair Javaid 3533a56363aSOmair Javaid Error error; 354ea8c25a8SOmair Javaid 3553a56363aSOmair Javaid // Read hardware breakpoint and watchpoint information. 3563a56363aSOmair Javaid error = ReadHardwareDebugInfo(); 3573a56363aSOmair Javaid 3583a56363aSOmair Javaid if (error.Fail()) 3593a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 3603a56363aSOmair Javaid 3613a56363aSOmair Javaid uint32_t control_value = 0, bp_index = 0; 362ea8c25a8SOmair Javaid 363ea8c25a8SOmair Javaid // Check if size has a valid hardware breakpoint length. 364ea8c25a8SOmair Javaid if (size != 4) 365*b9c1b51eSKate Stone return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware 366*b9c1b51eSKate Stone // breakpoint 367ea8c25a8SOmair Javaid 368ea8c25a8SOmair Javaid // Check 4-byte alignment for hardware breakpoint target address. 369ea8c25a8SOmair Javaid if (addr & 0x03) 370ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. 371ea8c25a8SOmair Javaid 372ea8c25a8SOmair Javaid // Setup control value 373ea8c25a8SOmair Javaid control_value = 0; 374ea8c25a8SOmair Javaid control_value |= ((1 << size) - 1) << 5; 375ea8c25a8SOmair Javaid control_value |= (2 << 1) | 1; 376ea8c25a8SOmair Javaid 377ea8c25a8SOmair Javaid // Iterate over stored hardware breakpoints 378ea8c25a8SOmair Javaid // Find a free bp_index or update reference count if duplicate. 379ea8c25a8SOmair Javaid bp_index = LLDB_INVALID_INDEX32; 380*b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 381*b9c1b51eSKate Stone if ((m_hbr_regs[i].control & 1) == 0) { 382ea8c25a8SOmair Javaid bp_index = i; // Mark last free slot 383*b9c1b51eSKate Stone } else if (m_hbr_regs[i].address == addr && 384*b9c1b51eSKate Stone m_hbr_regs[i].control == control_value) { 385ea8c25a8SOmair Javaid bp_index = i; // Mark duplicate index 386ea8c25a8SOmair Javaid break; // Stop searching here 387ea8c25a8SOmair Javaid } 388ea8c25a8SOmair Javaid } 389ea8c25a8SOmair Javaid 390ea8c25a8SOmair Javaid if (bp_index == LLDB_INVALID_INDEX32) 391ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; 392ea8c25a8SOmair Javaid 393f24741d9SOmair Javaid // Add new or update existing breakpoint 394*b9c1b51eSKate Stone if ((m_hbr_regs[bp_index].control & 1) == 0) { 395ea8c25a8SOmair Javaid m_hbr_regs[bp_index].address = addr; 396ea8c25a8SOmair Javaid m_hbr_regs[bp_index].control = control_value; 397ea8c25a8SOmair Javaid m_hbr_regs[bp_index].refcount = 1; 398ea8c25a8SOmair Javaid 3991fd2a8cfSOmair Javaid // PTRACE call to set corresponding hardware breakpoint register. 4003a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK); 4013a56363aSOmair Javaid 402*b9c1b51eSKate Stone if (error.Fail()) { 403f24741d9SOmair Javaid m_hbr_regs[bp_index].address = 0; 404f24741d9SOmair Javaid m_hbr_regs[bp_index].control &= ~1; 405f24741d9SOmair Javaid m_hbr_regs[bp_index].refcount = 0; 406f24741d9SOmair Javaid 4073a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 408ea8c25a8SOmair Javaid } 409*b9c1b51eSKate Stone } else 410ea8c25a8SOmair Javaid m_hbr_regs[bp_index].refcount++; 411ea8c25a8SOmair Javaid 412ea8c25a8SOmair Javaid return bp_index; 413ea8c25a8SOmair Javaid } 414ea8c25a8SOmair Javaid 415*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint( 416*b9c1b51eSKate Stone uint32_t hw_idx) { 417ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 418ea8c25a8SOmair Javaid 419ea8c25a8SOmair Javaid if (log) 420ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 421ea8c25a8SOmair Javaid 4223a56363aSOmair Javaid Error error; 4233a56363aSOmair Javaid 4241fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 4253a56363aSOmair Javaid error = ReadHardwareDebugInfo(); 4263a56363aSOmair Javaid 4273a56363aSOmair Javaid if (error.Fail()) 4283a56363aSOmair Javaid return false; 4291fd2a8cfSOmair Javaid 430ea8c25a8SOmair Javaid if (hw_idx >= m_max_hbp_supported) 431ea8c25a8SOmair Javaid return false; 432ea8c25a8SOmair Javaid 433ea8c25a8SOmair Javaid // Update reference count if multiple references. 434*b9c1b51eSKate Stone if (m_hbr_regs[hw_idx].refcount > 1) { 435ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].refcount--; 436ea8c25a8SOmair Javaid return true; 437*b9c1b51eSKate Stone } else if (m_hbr_regs[hw_idx].refcount == 1) { 438f24741d9SOmair Javaid // Create a backup we can revert to in case of failure. 439f24741d9SOmair Javaid lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; 440f24741d9SOmair Javaid uint32_t tempControl = m_hbr_regs[hw_idx].control; 441f24741d9SOmair Javaid uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount; 442f24741d9SOmair Javaid 443ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].control &= ~1; 444ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].address = 0; 445ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].refcount = 0; 446ea8c25a8SOmair Javaid 4471fd2a8cfSOmair Javaid // PTRACE call to clear corresponding hardware breakpoint register. 4481fd2a8cfSOmair Javaid WriteHardwareDebugRegs(eDREGTypeBREAK); 4493a56363aSOmair Javaid 450*b9c1b51eSKate Stone if (error.Fail()) { 451f24741d9SOmair Javaid m_hbr_regs[hw_idx].control = tempControl; 452f24741d9SOmair Javaid m_hbr_regs[hw_idx].address = tempAddr; 453f24741d9SOmair Javaid m_hbr_regs[hw_idx].refcount = tempRefCount; 454f24741d9SOmair Javaid 4553a56363aSOmair Javaid return false; 456f24741d9SOmair Javaid } 4573a56363aSOmair Javaid 4583a56363aSOmair Javaid return true; 459ea8c25a8SOmair Javaid } 460ea8c25a8SOmair Javaid 461ea8c25a8SOmair Javaid return false; 462ea8c25a8SOmair Javaid } 463ea8c25a8SOmair Javaid 464*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints() { 465ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 466ea8c25a8SOmair Javaid 467ea8c25a8SOmair Javaid if (log) 468ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 469ea8c25a8SOmair Javaid 4703a56363aSOmair Javaid Error error; 4713a56363aSOmair Javaid 4721fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 4733a56363aSOmair Javaid error = ReadHardwareDebugInfo(); 4743a56363aSOmair Javaid 4753a56363aSOmair Javaid if (error.Fail()) 47662661473SOmair Javaid return 0; 4771fd2a8cfSOmair Javaid 478ea8c25a8SOmair Javaid return m_max_hwp_supported; 479ea8c25a8SOmair Javaid } 480ea8c25a8SOmair Javaid 481*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::SetHardwareWatchpoint( 482*b9c1b51eSKate Stone lldb::addr_t addr, size_t size, uint32_t watch_flags) { 483ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 484ea8c25a8SOmair Javaid 485ea8c25a8SOmair Javaid if (log) 486ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 487ea8c25a8SOmair Javaid 4883a56363aSOmair Javaid Error error; 489ea8c25a8SOmair Javaid 4903a56363aSOmair Javaid // Read hardware breakpoint and watchpoint information. 4913a56363aSOmair Javaid error = ReadHardwareDebugInfo(); 4923a56363aSOmair Javaid 4933a56363aSOmair Javaid if (error.Fail()) 4943a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 4953a56363aSOmair Javaid 4963a56363aSOmair Javaid uint32_t control_value = 0, wp_index = 0; 49743507f57SOmair Javaid lldb::addr_t real_addr = addr; 498ea8c25a8SOmair Javaid 4991fd2a8cfSOmair Javaid // Check if we are setting watchpoint other than read/write/access 5001fd2a8cfSOmair Javaid // Also update watchpoint flag to match AArch64 write-read bit configuration. 501*b9c1b51eSKate Stone switch (watch_flags) { 5021fd2a8cfSOmair Javaid case 1: 5031fd2a8cfSOmair Javaid watch_flags = 2; 5041fd2a8cfSOmair Javaid break; 5051fd2a8cfSOmair Javaid case 2: 5061fd2a8cfSOmair Javaid watch_flags = 1; 5071fd2a8cfSOmair Javaid break; 5081fd2a8cfSOmair Javaid case 3: 5091fd2a8cfSOmair Javaid break; 5101fd2a8cfSOmair Javaid default: 5111fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 5121fd2a8cfSOmair Javaid } 513ea8c25a8SOmair Javaid 514ea8c25a8SOmair Javaid // Check if size has a valid hardware watchpoint length. 515ea8c25a8SOmair Javaid if (size != 1 && size != 2 && size != 4 && size != 8) 5161fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 517ea8c25a8SOmair Javaid 518ea8c25a8SOmair Javaid // Check 8-byte alignment for hardware watchpoint target address. 51943507f57SOmair Javaid // Below is a hack to recalculate address and size in order to 52043507f57SOmair Javaid // make sure we can watch non 8-byte alligned addresses as well. 521*b9c1b51eSKate Stone if (addr & 0x07) { 52243507f57SOmair Javaid uint8_t watch_mask = (addr & 0x07) + size; 52343507f57SOmair Javaid 52443507f57SOmair Javaid if (watch_mask > 0x08) 5251fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 52643507f57SOmair Javaid else if (watch_mask <= 0x02) 52743507f57SOmair Javaid size = 2; 52843507f57SOmair Javaid else if (watch_mask <= 0x04) 52943507f57SOmair Javaid size = 4; 53043507f57SOmair Javaid else 53143507f57SOmair Javaid size = 8; 53243507f57SOmair Javaid 53343507f57SOmair Javaid addr = addr & (~0x07); 53443507f57SOmair Javaid } 535ea8c25a8SOmair Javaid 536ea8c25a8SOmair Javaid // Setup control value 537ea8c25a8SOmair Javaid control_value = watch_flags << 3; 538ea8c25a8SOmair Javaid control_value |= ((1 << size) - 1) << 5; 539ea8c25a8SOmair Javaid control_value |= (2 << 1) | 1; 540ea8c25a8SOmair Javaid 541ea8c25a8SOmair Javaid // Iterate over stored watchpoints 542ea8c25a8SOmair Javaid // Find a free wp_index or update reference count if duplicate. 543ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 544*b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 545*b9c1b51eSKate Stone if ((m_hwp_regs[i].control & 1) == 0) { 546ea8c25a8SOmair Javaid wp_index = i; // Mark last free slot 547*b9c1b51eSKate Stone } else if (m_hwp_regs[i].address == addr && 548*b9c1b51eSKate Stone m_hwp_regs[i].control == control_value) { 549ea8c25a8SOmair Javaid wp_index = i; // Mark duplicate index 550ea8c25a8SOmair Javaid break; // Stop searching here 551ea8c25a8SOmair Javaid } 552ea8c25a8SOmair Javaid } 553ea8c25a8SOmair Javaid 554ea8c25a8SOmair Javaid if (wp_index == LLDB_INVALID_INDEX32) 555ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; 556ea8c25a8SOmair Javaid 557ea8c25a8SOmair Javaid // Add new or update existing watchpoint 558*b9c1b51eSKate Stone if ((m_hwp_regs[wp_index].control & 1) == 0) { 5591fd2a8cfSOmair Javaid // Update watchpoint in local cache 56043507f57SOmair Javaid m_hwp_regs[wp_index].real_addr = real_addr; 561ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = addr; 562ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control = control_value; 563ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount = 1; 564ea8c25a8SOmair Javaid 565ea8c25a8SOmair Javaid // PTRACE call to set corresponding watchpoint register. 5663a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 5673a56363aSOmair Javaid 568*b9c1b51eSKate Stone if (error.Fail()) { 569f24741d9SOmair Javaid m_hwp_regs[wp_index].address = 0; 570f24741d9SOmair Javaid m_hwp_regs[wp_index].control &= ~1; 571f24741d9SOmair Javaid m_hwp_regs[wp_index].refcount = 0; 572f24741d9SOmair Javaid 5733a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 574ea8c25a8SOmair Javaid } 575*b9c1b51eSKate Stone } else 576ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount++; 577ea8c25a8SOmair Javaid 578ea8c25a8SOmair Javaid return wp_index; 579ea8c25a8SOmair Javaid } 580ea8c25a8SOmair Javaid 581*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint( 582*b9c1b51eSKate Stone uint32_t wp_index) { 583ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 584ea8c25a8SOmair Javaid 585ea8c25a8SOmair Javaid if (log) 586ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 587ea8c25a8SOmair Javaid 5883a56363aSOmair Javaid Error error; 5893a56363aSOmair Javaid 5901fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 5913a56363aSOmair Javaid error = ReadHardwareDebugInfo(); 5923a56363aSOmair Javaid 5933a56363aSOmair Javaid if (error.Fail()) 5943a56363aSOmair Javaid return false; 595ea8c25a8SOmair Javaid 596ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 597ea8c25a8SOmair Javaid return false; 598ea8c25a8SOmair Javaid 599ea8c25a8SOmair Javaid // Update reference count if multiple references. 600*b9c1b51eSKate Stone if (m_hwp_regs[wp_index].refcount > 1) { 601ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount--; 602ea8c25a8SOmair Javaid return true; 603*b9c1b51eSKate Stone } else if (m_hwp_regs[wp_index].refcount == 1) { 604f24741d9SOmair Javaid // Create a backup we can revert to in case of failure. 605f24741d9SOmair Javaid lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 606f24741d9SOmair Javaid uint32_t tempControl = m_hwp_regs[wp_index].control; 607f24741d9SOmair Javaid uint32_t tempRefCount = m_hwp_regs[wp_index].refcount; 608f24741d9SOmair Javaid 6091fd2a8cfSOmair Javaid // Update watchpoint in local cache 610ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control &= ~1; 611ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = 0; 612ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount = 0; 613ea8c25a8SOmair Javaid 6141fd2a8cfSOmair Javaid // Ptrace call to update hardware debug registers 6153a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 6163a56363aSOmair Javaid 617*b9c1b51eSKate Stone if (error.Fail()) { 618f24741d9SOmair Javaid m_hwp_regs[wp_index].control = tempControl; 619f24741d9SOmair Javaid m_hwp_regs[wp_index].address = tempAddr; 620f24741d9SOmair Javaid m_hwp_regs[wp_index].refcount = tempRefCount; 621f24741d9SOmair Javaid 6223a56363aSOmair Javaid return false; 623f24741d9SOmair Javaid } 6243a56363aSOmair Javaid 625ea8c25a8SOmair Javaid return true; 626ea8c25a8SOmair Javaid } 627ea8c25a8SOmair Javaid 628ea8c25a8SOmair Javaid return false; 629ea8c25a8SOmair Javaid } 630ea8c25a8SOmair Javaid 631*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints() { 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 error; 644ea8c25a8SOmair Javaid 645f24741d9SOmair Javaid lldb::addr_t tempAddr = 0; 646f24741d9SOmair Javaid uint32_t tempControl = 0, tempRefCount = 0; 647f24741d9SOmair Javaid 648*b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 649*b9c1b51eSKate Stone if (m_hwp_regs[i].control & 0x01) { 650f24741d9SOmair Javaid // Create a backup we can revert to in case of failure. 651f24741d9SOmair Javaid tempAddr = m_hwp_regs[i].address; 652f24741d9SOmair Javaid tempControl = m_hwp_regs[i].control; 653f24741d9SOmair Javaid tempRefCount = m_hwp_regs[i].refcount; 654f24741d9SOmair Javaid 6551fd2a8cfSOmair Javaid // Clear watchpoints in local cache 656ea8c25a8SOmair Javaid m_hwp_regs[i].control &= ~1; 657ea8c25a8SOmair Javaid m_hwp_regs[i].address = 0; 658ea8c25a8SOmair Javaid m_hwp_regs[i].refcount = 0; 659ea8c25a8SOmair Javaid 6601fd2a8cfSOmair Javaid // Ptrace call to update hardware debug registers 6613a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 6623a56363aSOmair Javaid 663*b9c1b51eSKate Stone if (error.Fail()) { 664f24741d9SOmair Javaid m_hwp_regs[i].control = tempControl; 665f24741d9SOmair Javaid m_hwp_regs[i].address = tempAddr; 666f24741d9SOmair Javaid m_hwp_regs[i].refcount = tempRefCount; 667f24741d9SOmair Javaid 6683a56363aSOmair Javaid return error; 669ea8c25a8SOmair Javaid } 670ea8c25a8SOmair Javaid } 671f24741d9SOmair Javaid } 672ea8c25a8SOmair Javaid 673ea8c25a8SOmair Javaid return Error(); 674ea8c25a8SOmair Javaid } 675ea8c25a8SOmair Javaid 676ea8c25a8SOmair Javaid uint32_t 677*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) { 678ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 679ea8c25a8SOmair Javaid 680ea8c25a8SOmair Javaid if (log) 681ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 682*b9c1b51eSKate Stone switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) { 683ea8c25a8SOmair Javaid case 0x01: 684ea8c25a8SOmair Javaid return 1; 685ea8c25a8SOmair Javaid case 0x03: 686ea8c25a8SOmair Javaid return 2; 687ea8c25a8SOmair Javaid case 0x0f: 688ea8c25a8SOmair Javaid return 4; 689ea8c25a8SOmair Javaid case 0xff: 690ea8c25a8SOmair Javaid return 8; 691ea8c25a8SOmair Javaid default: 692ea8c25a8SOmair Javaid return 0; 693ea8c25a8SOmair Javaid } 694ea8c25a8SOmair Javaid } 695*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) { 696ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 697ea8c25a8SOmair Javaid 698ea8c25a8SOmair Javaid if (log) 699ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 700ea8c25a8SOmair Javaid 701ea8c25a8SOmair Javaid if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 702ea8c25a8SOmair Javaid return true; 703ea8c25a8SOmair Javaid else 704ea8c25a8SOmair Javaid return false; 705ea8c25a8SOmair Javaid } 706ea8c25a8SOmair Javaid 707*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::GetWatchpointHitIndex( 708*b9c1b51eSKate Stone uint32_t &wp_index, lldb::addr_t trap_addr) { 709ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 710ea8c25a8SOmair Javaid 711ea8c25a8SOmair Javaid if (log) 712ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 713ea8c25a8SOmair Javaid 714ea8c25a8SOmair Javaid uint32_t watch_size; 715ea8c25a8SOmair Javaid lldb::addr_t watch_addr; 716ea8c25a8SOmair Javaid 717*b9c1b51eSKate Stone for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { 718ea8c25a8SOmair Javaid watch_size = GetWatchpointSize(wp_index); 719ea8c25a8SOmair Javaid watch_addr = m_hwp_regs[wp_index].address; 720ea8c25a8SOmair Javaid 721*b9c1b51eSKate Stone if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) && 722*b9c1b51eSKate Stone trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) { 72343507f57SOmair Javaid m_hwp_regs[wp_index].hit_addr = trap_addr; 724ea8c25a8SOmair Javaid return Error(); 725ea8c25a8SOmair Javaid } 726ea8c25a8SOmair Javaid } 727ea8c25a8SOmair Javaid 728ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 729ea8c25a8SOmair Javaid return Error(); 730ea8c25a8SOmair Javaid } 731ea8c25a8SOmair Javaid 732ea8c25a8SOmair Javaid lldb::addr_t 733*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointAddress(uint32_t wp_index) { 734ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 735ea8c25a8SOmair Javaid 736ea8c25a8SOmair Javaid if (log) 737ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 738ea8c25a8SOmair Javaid 739ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 740ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 741ea8c25a8SOmair Javaid 742ea8c25a8SOmair Javaid if (WatchpointIsEnabled(wp_index)) 74343507f57SOmair Javaid return m_hwp_regs[wp_index].real_addr; 74443507f57SOmair Javaid else 74543507f57SOmair Javaid return LLDB_INVALID_ADDRESS; 74643507f57SOmair Javaid } 74743507f57SOmair Javaid 74843507f57SOmair Javaid lldb::addr_t 749*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointHitAddress(uint32_t wp_index) { 75043507f57SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 75143507f57SOmair Javaid 75243507f57SOmair Javaid if (log) 75343507f57SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 75443507f57SOmair Javaid 75543507f57SOmair Javaid if (wp_index >= m_max_hwp_supported) 75643507f57SOmair Javaid return LLDB_INVALID_ADDRESS; 75743507f57SOmair Javaid 75843507f57SOmair Javaid if (WatchpointIsEnabled(wp_index)) 75943507f57SOmair Javaid return m_hwp_regs[wp_index].hit_addr; 760ea8c25a8SOmair Javaid else 761ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 762ea8c25a8SOmair Javaid } 763ea8c25a8SOmair Javaid 764*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { 765*b9c1b51eSKate Stone if (!m_refresh_hwdebug_info) { 7661fd2a8cfSOmair Javaid return Error(); 7671fd2a8cfSOmair Javaid } 7681fd2a8cfSOmair Javaid 769c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 770ea8c25a8SOmair Javaid 771c7512fdcSPavel Labath int regset = NT_ARM_HW_WATCH; 772c7512fdcSPavel Labath struct iovec ioVec; 773c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 774c7512fdcSPavel Labath Error error; 775c7512fdcSPavel Labath 776c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 777c7512fdcSPavel Labath ioVec.iov_len = sizeof(dreg_state); 778*b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 779*b9c1b51eSKate Stone &ioVec, ioVec.iov_len); 7803a56363aSOmair Javaid 7813a56363aSOmair Javaid if (error.Fail()) 7823a56363aSOmair Javaid return error; 7833a56363aSOmair Javaid 7841fd2a8cfSOmair Javaid m_max_hwp_supported = dreg_state.dbg_info & 0xff; 785c7512fdcSPavel Labath 786c7512fdcSPavel Labath regset = NT_ARM_HW_BREAK; 787*b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 788*b9c1b51eSKate Stone &ioVec, ioVec.iov_len); 7891fd2a8cfSOmair Javaid 7903a56363aSOmair Javaid if (error.Fail()) 7913a56363aSOmair Javaid return error; 7923a56363aSOmair Javaid 7933a56363aSOmair 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 799*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) { 800c7512fdcSPavel Labath struct iovec ioVec; 801c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 802c7512fdcSPavel Labath Error error; 803c7512fdcSPavel Labath 804c7512fdcSPavel Labath memset(&dreg_state, 0, sizeof(dreg_state)); 805c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 806c7512fdcSPavel Labath 807*b9c1b51eSKate Stone if (hwbType == eDREGTypeWATCH) { 8081fd2a8cfSOmair Javaid hwbType = NT_ARM_HW_WATCH; 809*b9c1b51eSKate Stone ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + 810*b9c1b51eSKate Stone (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported); 8111fd2a8cfSOmair Javaid 812*b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 8131fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; 8141fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; 8151fd2a8cfSOmair Javaid } 816*b9c1b51eSKate Stone } else { 8171fd2a8cfSOmair Javaid hwbType = NT_ARM_HW_BREAK; 818*b9c1b51eSKate Stone ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + 819*b9c1b51eSKate Stone (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported); 8201fd2a8cfSOmair Javaid 821*b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 8221fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address; 8231fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control; 8241fd2a8cfSOmair Javaid } 825068f8a7eSTamas Berghammer } 826068f8a7eSTamas Berghammer 827*b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), 828*b9c1b51eSKate Stone &hwbType, &ioVec, ioVec.iov_len); 829c7512fdcSPavel Labath } 830c7512fdcSPavel Labath 831*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadRegisterValue( 832*b9c1b51eSKate Stone uint32_t offset, const char *reg_name, uint32_t size, 833*b9c1b51eSKate Stone RegisterValue &value) { 834c7512fdcSPavel Labath Error error; 835*b9c1b51eSKate Stone if (offset > sizeof(struct user_pt_regs)) { 836c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 837*b9c1b51eSKate Stone if (offset > sizeof(struct user_fpsimd_state)) { 838c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 839c7512fdcSPavel Labath return error; 840c7512fdcSPavel Labath } 841c7512fdcSPavel Labath elf_fpregset_t regs; 842c7512fdcSPavel Labath int regset = NT_FPREGSET; 843c7512fdcSPavel Labath struct iovec ioVec; 844c7512fdcSPavel Labath 845c7512fdcSPavel Labath ioVec.iov_base = ®s; 846c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 8474a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 8484a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 849*b9c1b51eSKate Stone if (error.Success()) { 850c7512fdcSPavel Labath ArchSpec arch; 851c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 852*b9c1b51eSKate Stone value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, 853*b9c1b51eSKate Stone arch.GetByteOrder()); 854c7512fdcSPavel Labath else 855c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 856c7512fdcSPavel Labath } 857*b9c1b51eSKate Stone } else { 858c7512fdcSPavel Labath elf_gregset_t regs; 859c7512fdcSPavel Labath int regset = NT_PRSTATUS; 860c7512fdcSPavel Labath struct iovec ioVec; 861c7512fdcSPavel Labath 862c7512fdcSPavel Labath ioVec.iov_base = ®s; 863c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 8644a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 8654a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 866*b9c1b51eSKate Stone if (error.Success()) { 867c7512fdcSPavel Labath ArchSpec arch; 868c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 869*b9c1b51eSKate Stone value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, 870*b9c1b51eSKate Stone arch.GetByteOrder()); 871c7512fdcSPavel Labath else 872c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 873c7512fdcSPavel Labath } 874c7512fdcSPavel Labath } 875c7512fdcSPavel Labath return error; 876068f8a7eSTamas Berghammer } 877068f8a7eSTamas Berghammer 878*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteRegisterValue( 879*b9c1b51eSKate Stone uint32_t offset, const char *reg_name, const RegisterValue &value) { 880c7512fdcSPavel Labath Error error; 881c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 882*b9c1b51eSKate Stone if (offset > sizeof(struct user_pt_regs)) { 883c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 884*b9c1b51eSKate Stone if (offset > sizeof(struct user_fpsimd_state)) { 885c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 886c7512fdcSPavel Labath return error; 887c7512fdcSPavel Labath } 888c7512fdcSPavel Labath elf_fpregset_t regs; 889c7512fdcSPavel Labath int regset = NT_FPREGSET; 890c7512fdcSPavel Labath struct iovec ioVec; 891c7512fdcSPavel Labath 892c7512fdcSPavel Labath ioVec.iov_base = ®s; 893c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 894*b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 895*b9c1b51eSKate Stone &ioVec, sizeof regs); 896c7512fdcSPavel Labath 897*b9c1b51eSKate Stone if (error.Success()) { 898*b9c1b51eSKate Stone ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 899*b9c1b51eSKate Stone 16); 900*b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, 901*b9c1b51eSKate Stone &ioVec, sizeof regs); 902c7512fdcSPavel Labath } 903*b9c1b51eSKate Stone } else { 904c7512fdcSPavel Labath elf_gregset_t regs; 905c7512fdcSPavel Labath int regset = NT_PRSTATUS; 906c7512fdcSPavel Labath struct iovec ioVec; 907c7512fdcSPavel Labath 908c7512fdcSPavel Labath ioVec.iov_base = ®s; 909c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 910*b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 911*b9c1b51eSKate Stone &ioVec, sizeof regs); 912*b9c1b51eSKate Stone if (error.Success()) { 913*b9c1b51eSKate Stone ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 914*b9c1b51eSKate Stone 8); 915*b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, 916*b9c1b51eSKate Stone &ioVec, sizeof regs); 917c7512fdcSPavel Labath } 918c7512fdcSPavel Labath } 919c7512fdcSPavel Labath return error; 920068f8a7eSTamas Berghammer } 921068f8a7eSTamas Berghammer 922*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) { 923c7512fdcSPavel Labath int regset = NT_PRSTATUS; 924c7512fdcSPavel Labath struct iovec ioVec; 925c7512fdcSPavel Labath Error error; 926c7512fdcSPavel Labath 927c7512fdcSPavel Labath ioVec.iov_base = buf; 928c7512fdcSPavel Labath ioVec.iov_len = buf_size; 929*b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), 930*b9c1b51eSKate Stone ®set, &ioVec, buf_size); 931068f8a7eSTamas Berghammer } 932068f8a7eSTamas Berghammer 933*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) { 934c7512fdcSPavel Labath int regset = NT_PRSTATUS; 935c7512fdcSPavel Labath struct iovec ioVec; 936c7512fdcSPavel Labath Error error; 937c7512fdcSPavel Labath 938c7512fdcSPavel Labath ioVec.iov_base = buf; 939c7512fdcSPavel Labath ioVec.iov_len = buf_size; 940*b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), 941*b9c1b51eSKate Stone ®set, &ioVec, buf_size); 942068f8a7eSTamas Berghammer } 943068f8a7eSTamas Berghammer 944*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) { 945c7512fdcSPavel Labath int regset = NT_FPREGSET; 946c7512fdcSPavel Labath struct iovec ioVec; 947c7512fdcSPavel Labath Error error; 948c7512fdcSPavel Labath 949c7512fdcSPavel Labath ioVec.iov_base = buf; 950c7512fdcSPavel Labath ioVec.iov_len = buf_size; 951*b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), 952*b9c1b51eSKate Stone ®set, &ioVec, buf_size); 953068f8a7eSTamas Berghammer } 954068f8a7eSTamas Berghammer 955*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) { 956c7512fdcSPavel Labath int regset = NT_FPREGSET; 957c7512fdcSPavel Labath struct iovec ioVec; 958c7512fdcSPavel Labath Error error; 959c7512fdcSPavel Labath 960c7512fdcSPavel Labath ioVec.iov_base = buf; 961c7512fdcSPavel Labath ioVec.iov_len = buf_size; 962*b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), 963*b9c1b51eSKate Stone ®set, &ioVec, buf_size); 964068f8a7eSTamas Berghammer } 965068f8a7eSTamas Berghammer 966*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset( 967*b9c1b51eSKate Stone const RegisterInfo *reg_info) const { 968*b9c1b51eSKate Stone return reg_info->byte_offset - 969*b9c1b51eSKate Stone GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; 970c40e7b17STamas Berghammer } 971c40e7b17STamas Berghammer 972068f8a7eSTamas Berghammer #endif // defined (__arm64__) || defined (__aarch64__) 973