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 30b9c1b51eSKate Stone // System includes - They have to be included after framework includes because 31b9c1b51eSKate 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. 46b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_arm64[] = { 47b9c1b51eSKate Stone gpr_x0_arm64, gpr_x1_arm64, gpr_x2_arm64, gpr_x3_arm64, 48b9c1b51eSKate Stone gpr_x4_arm64, gpr_x5_arm64, gpr_x6_arm64, gpr_x7_arm64, 49b9c1b51eSKate Stone gpr_x8_arm64, gpr_x9_arm64, gpr_x10_arm64, gpr_x11_arm64, 50b9c1b51eSKate Stone gpr_x12_arm64, gpr_x13_arm64, gpr_x14_arm64, gpr_x15_arm64, 51b9c1b51eSKate Stone gpr_x16_arm64, gpr_x17_arm64, gpr_x18_arm64, gpr_x19_arm64, 52b9c1b51eSKate Stone gpr_x20_arm64, gpr_x21_arm64, gpr_x22_arm64, gpr_x23_arm64, 53b9c1b51eSKate Stone gpr_x24_arm64, gpr_x25_arm64, gpr_x26_arm64, gpr_x27_arm64, 54b9c1b51eSKate Stone gpr_x28_arm64, gpr_fp_arm64, gpr_lr_arm64, gpr_sp_arm64, 55b9c1b51eSKate Stone gpr_pc_arm64, gpr_cpsr_arm64, 561e209fccSTamas Berghammer LLDB_INVALID_REGNUM // register sets need to end with this flag 571e209fccSTamas Berghammer }; 58b9c1b51eSKate Stone static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 59b9c1b51eSKate 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. 63b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_arm64[] = { 64b9c1b51eSKate Stone fpu_v0_arm64, fpu_v1_arm64, fpu_v2_arm64, fpu_v3_arm64, 65b9c1b51eSKate Stone fpu_v4_arm64, fpu_v5_arm64, fpu_v6_arm64, fpu_v7_arm64, 66b9c1b51eSKate Stone fpu_v8_arm64, fpu_v9_arm64, fpu_v10_arm64, fpu_v11_arm64, 67b9c1b51eSKate Stone fpu_v12_arm64, fpu_v13_arm64, fpu_v14_arm64, fpu_v15_arm64, 68b9c1b51eSKate Stone fpu_v16_arm64, fpu_v17_arm64, fpu_v18_arm64, fpu_v19_arm64, 69b9c1b51eSKate Stone fpu_v20_arm64, fpu_v21_arm64, fpu_v22_arm64, fpu_v23_arm64, 70b9c1b51eSKate Stone fpu_v24_arm64, fpu_v25_arm64, fpu_v26_arm64, fpu_v27_arm64, 71b9c1b51eSKate Stone fpu_v28_arm64, fpu_v29_arm64, fpu_v30_arm64, fpu_v31_arm64, 72b9c1b51eSKate Stone fpu_fpsr_arm64, fpu_fpcr_arm64, 731e209fccSTamas Berghammer LLDB_INVALID_REGNUM // register sets need to end with this flag 741e209fccSTamas Berghammer }; 75b9c1b51eSKate Stone static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 76b9c1b51eSKate 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. 81b9c1b51eSKate Stone enum { k_num_register_sets = 2 }; 821e209fccSTamas Berghammer } 831e209fccSTamas Berghammer 841e209fccSTamas Berghammer // Register sets for ARM64. 85b9c1b51eSKate Stone static const RegisterSet g_reg_sets_arm64[k_num_register_sets] = { 86b9c1b51eSKate Stone {"General Purpose Registers", "gpr", k_num_gpr_registers_arm64, 87b9c1b51eSKate Stone g_gpr_regnums_arm64}, 88b9c1b51eSKate Stone {"Floating Point Registers", "fpu", k_num_fpr_registers_arm64, 89b9c1b51eSKate Stone g_fpu_regnums_arm64}}; 901e209fccSTamas Berghammer 91068f8a7eSTamas Berghammer NativeRegisterContextLinux * 92b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 93b9c1b51eSKate Stone const ArchSpec &target_arch, NativeThreadProtocol &native_thread, 94b9c1b51eSKate Stone uint32_t concrete_frame_idx) { 95e85e6021STamas Berghammer Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS); 96b9c1b51eSKate Stone switch (target_arch.GetMachine()) { 97e85e6021STamas Berghammer case llvm::Triple::arm: 98b9c1b51eSKate Stone return new NativeRegisterContextLinux_arm(target_arch, native_thread, 99b9c1b51eSKate Stone concrete_frame_idx); 100e85e6021STamas Berghammer case llvm::Triple::aarch64: 101b9c1b51eSKate Stone return new NativeRegisterContextLinux_arm64(target_arch, native_thread, 102b9c1b51eSKate Stone concrete_frame_idx); 103e85e6021STamas Berghammer default: 104e85e6021STamas Berghammer if (log) 105b9c1b51eSKate Stone log->Printf("NativeRegisterContextLinux::%s() have no register context " 106b9c1b51eSKate Stone "for architecture: %s\n", 107b9c1b51eSKate Stone __FUNCTION__, 108e85e6021STamas Berghammer target_arch.GetTriple().getArchName().str().c_str()); 109e85e6021STamas Berghammer return nullptr; 110e85e6021STamas Berghammer } 111068f8a7eSTamas Berghammer } 112068f8a7eSTamas Berghammer 113b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64( 114b9c1b51eSKate Stone const ArchSpec &target_arch, NativeThreadProtocol &native_thread, 115b9c1b51eSKate Stone uint32_t concrete_frame_idx) 116b9c1b51eSKate Stone : NativeRegisterContextLinux(native_thread, concrete_frame_idx, 117b9c1b51eSKate Stone new RegisterContextLinux_arm64(target_arch)) { 118b9c1b51eSKate 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 145b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::GetRegisterSetCount() const { 1461e209fccSTamas Berghammer return k_num_register_sets; 1471e209fccSTamas Berghammer } 1481e209fccSTamas Berghammer 149db264a6dSTamas Berghammer const RegisterSet * 150b9c1b51eSKate 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 157b9c1b51eSKate 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 164b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadRegister( 165b9c1b51eSKate Stone const RegisterInfo *reg_info, RegisterValue ®_value) { 1661e209fccSTamas Berghammer Error error; 1671e209fccSTamas Berghammer 168b9c1b51eSKate 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 175b9c1b51eSKate Stone if (IsFPR(reg)) { 176068f8a7eSTamas Berghammer error = ReadFPR(); 177068f8a7eSTamas Berghammer if (error.Fail()) 1781e209fccSTamas Berghammer return error; 179b9c1b51eSKate Stone } else { 1801e209fccSTamas Berghammer uint32_t full_reg = reg; 181b9c1b51eSKate Stone bool is_subreg = reg_info->invalidate_regs && 182b9c1b51eSKate Stone (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 1831e209fccSTamas Berghammer 184b9c1b51eSKate 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 191b9c1b51eSKate Stone if (error.Success()) { 192b9c1b51eSKate Stone // If our read was not aligned (for ah,bh,ch,dh), shift our returned value 193b9c1b51eSKate 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 197b9c1b51eSKate Stone // If our return byte size was greater than the return value reg size, 198b9c1b51eSKate 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; 210b9c1b51eSKate Stone reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, 211b9c1b51eSKate Stone eByteOrderLittle, error); 2121e209fccSTamas Berghammer 2131e209fccSTamas Berghammer return error; 2141e209fccSTamas Berghammer } 2151e209fccSTamas Berghammer 216b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteRegister( 217b9c1b51eSKate 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) 223b9c1b51eSKate Stone return Error("no lldb regnum for %s", reg_info && reg_info->name 224b9c1b51eSKate Stone ? reg_info->name 225b9c1b51eSKate Stone : "<unknown register>"); 2261e209fccSTamas Berghammer 2271e209fccSTamas Berghammer if (IsGPR(reg_index)) 2281e209fccSTamas Berghammer return WriteRegisterRaw(reg_index, reg_value); 2291e209fccSTamas Berghammer 230b9c1b51eSKate 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; 235b9c1b51eSKate 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."); 247b9c1b51eSKate Stone return Error("unhandled register data size %" PRIu32, 248b9c1b51eSKate 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 258b9c1b51eSKate Stone return Error("failed - register wasn't recognized to be a GPR or an FPR, " 259b9c1b51eSKate Stone "write strategy unknown"); 2601e209fccSTamas Berghammer } 2611e209fccSTamas Berghammer 262b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadAllRegisterValues( 263b9c1b51eSKate 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) 268b9c1b51eSKate Stone return Error("failed to allocate DataBufferHeap instance of size %" PRIu64, 269b9c1b51eSKate 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(); 280b9c1b51eSKate Stone if (dst == nullptr) { 281b9c1b51eSKate Stone error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 282b9c1b51eSKate Stone " returned a null pointer", 283b9c1b51eSKate 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 294b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteAllRegisterValues( 295b9c1b51eSKate Stone const lldb::DataBufferSP &data_sp) { 2961e209fccSTamas Berghammer Error error; 2971e209fccSTamas Berghammer 298b9c1b51eSKate Stone if (!data_sp) { 299b9c1b51eSKate Stone error.SetErrorStringWithFormat( 300b9c1b51eSKate Stone "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", 301b9c1b51eSKate Stone __FUNCTION__); 3021e209fccSTamas Berghammer return error; 3031e209fccSTamas Berghammer } 3041e209fccSTamas Berghammer 305b9c1b51eSKate Stone if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 306b9c1b51eSKate Stone error.SetErrorStringWithFormat( 307b9c1b51eSKate Stone "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " 308b9c1b51eSKate Stone "data size, expected %" PRIu64 ", actual %" PRIu64, 309b9c1b51eSKate Stone __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 3101e209fccSTamas Berghammer return error; 3111e209fccSTamas Berghammer } 3121e209fccSTamas Berghammer 3131e209fccSTamas Berghammer uint8_t *src = data_sp->GetBytes(); 314b9c1b51eSKate Stone if (src == nullptr) { 315b9c1b51eSKate Stone error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " 316b9c1b51eSKate Stone "DataBuffer::GetBytes() returned a null " 317b9c1b51eSKate Stone "pointer", 318b9c1b51eSKate 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 337b9c1b51eSKate 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 341b9c1b51eSKate 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 346b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::SetHardwareBreakpoint(lldb::addr_t addr, 347b9c1b51eSKate 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) 365b9c1b51eSKate Stone return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware 366b9c1b51eSKate 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; 380b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 381b9c1b51eSKate Stone if ((m_hbr_regs[i].control & 1) == 0) { 382ea8c25a8SOmair Javaid bp_index = i; // Mark last free slot 383b9c1b51eSKate Stone } else if (m_hbr_regs[i].address == addr && 384b9c1b51eSKate 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 394b9c1b51eSKate 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 402b9c1b51eSKate 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 } 409b9c1b51eSKate Stone } else 410ea8c25a8SOmair Javaid m_hbr_regs[bp_index].refcount++; 411ea8c25a8SOmair Javaid 412ea8c25a8SOmair Javaid return bp_index; 413ea8c25a8SOmair Javaid } 414ea8c25a8SOmair Javaid 415b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint( 416b9c1b51eSKate 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. 434b9c1b51eSKate Stone if (m_hbr_regs[hw_idx].refcount > 1) { 435ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].refcount--; 436ea8c25a8SOmair Javaid return true; 437b9c1b51eSKate 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 450b9c1b51eSKate 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 464b9c1b51eSKate 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 481b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::SetHardwareWatchpoint( 482b9c1b51eSKate 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. 501b9c1b51eSKate 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. 521b9c1b51eSKate 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 541*05ac4c44SOmair Javaid // Iterate over stored watchpoints and find a free wp_index 542ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 543b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 544b9c1b51eSKate Stone if ((m_hwp_regs[i].control & 1) == 0) { 545ea8c25a8SOmair Javaid wp_index = i; // Mark last free slot 546*05ac4c44SOmair Javaid } else if (m_hwp_regs[i].address == addr) { 547*05ac4c44SOmair Javaid return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. 548ea8c25a8SOmair Javaid } 549ea8c25a8SOmair Javaid } 550ea8c25a8SOmair Javaid 551ea8c25a8SOmair Javaid if (wp_index == LLDB_INVALID_INDEX32) 552ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; 553ea8c25a8SOmair Javaid 5541fd2a8cfSOmair Javaid // Update watchpoint in local cache 55543507f57SOmair Javaid m_hwp_regs[wp_index].real_addr = real_addr; 556ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = addr; 557ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control = control_value; 558ea8c25a8SOmair Javaid 559ea8c25a8SOmair Javaid // PTRACE call to set corresponding watchpoint register. 5603a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 5613a56363aSOmair Javaid 562b9c1b51eSKate Stone if (error.Fail()) { 563f24741d9SOmair Javaid m_hwp_regs[wp_index].address = 0; 564f24741d9SOmair Javaid m_hwp_regs[wp_index].control &= ~1; 565f24741d9SOmair Javaid 5663a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 567ea8c25a8SOmair Javaid } 568ea8c25a8SOmair Javaid 569ea8c25a8SOmair Javaid return wp_index; 570ea8c25a8SOmair Javaid } 571ea8c25a8SOmair Javaid 572b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint( 573b9c1b51eSKate Stone uint32_t wp_index) { 574ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 575ea8c25a8SOmair Javaid 576ea8c25a8SOmair Javaid if (log) 577ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 578ea8c25a8SOmair Javaid 5793a56363aSOmair Javaid Error error; 5803a56363aSOmair Javaid 5811fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 5823a56363aSOmair Javaid error = ReadHardwareDebugInfo(); 5833a56363aSOmair Javaid 5843a56363aSOmair Javaid if (error.Fail()) 5853a56363aSOmair Javaid return false; 586ea8c25a8SOmair Javaid 587ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 588ea8c25a8SOmair Javaid return false; 589ea8c25a8SOmair Javaid 590f24741d9SOmair Javaid // Create a backup we can revert to in case of failure. 591f24741d9SOmair Javaid lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 592f24741d9SOmair Javaid uint32_t tempControl = m_hwp_regs[wp_index].control; 593f24741d9SOmair Javaid 5941fd2a8cfSOmair Javaid // Update watchpoint in local cache 595ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control &= ~1; 596ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = 0; 597ea8c25a8SOmair Javaid 5981fd2a8cfSOmair Javaid // Ptrace call to update hardware debug registers 5993a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 6003a56363aSOmair Javaid 601b9c1b51eSKate Stone if (error.Fail()) { 602f24741d9SOmair Javaid m_hwp_regs[wp_index].control = tempControl; 603f24741d9SOmair Javaid m_hwp_regs[wp_index].address = tempAddr; 604f24741d9SOmair Javaid 6053a56363aSOmair Javaid return false; 606f24741d9SOmair Javaid } 6073a56363aSOmair Javaid 608ea8c25a8SOmair Javaid return true; 609ea8c25a8SOmair Javaid } 610ea8c25a8SOmair Javaid 611b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints() { 612ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 613ea8c25a8SOmair Javaid 614ea8c25a8SOmair Javaid if (log) 615ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 616ea8c25a8SOmair Javaid 6173a56363aSOmair Javaid Error error; 6183a56363aSOmair Javaid 6191fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 6203a56363aSOmair Javaid error = ReadHardwareDebugInfo(); 6213a56363aSOmair Javaid 6223a56363aSOmair Javaid if (error.Fail()) 6233a56363aSOmair Javaid return error; 624ea8c25a8SOmair Javaid 625f24741d9SOmair Javaid lldb::addr_t tempAddr = 0; 626f24741d9SOmair Javaid uint32_t tempControl = 0, tempRefCount = 0; 627f24741d9SOmair Javaid 628b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 629b9c1b51eSKate Stone if (m_hwp_regs[i].control & 0x01) { 630f24741d9SOmair Javaid // Create a backup we can revert to in case of failure. 631f24741d9SOmair Javaid tempAddr = m_hwp_regs[i].address; 632f24741d9SOmair Javaid tempControl = m_hwp_regs[i].control; 633f24741d9SOmair Javaid 6341fd2a8cfSOmair Javaid // Clear watchpoints in local cache 635ea8c25a8SOmair Javaid m_hwp_regs[i].control &= ~1; 636ea8c25a8SOmair Javaid m_hwp_regs[i].address = 0; 637ea8c25a8SOmair Javaid 6381fd2a8cfSOmair Javaid // Ptrace call to update hardware debug registers 6393a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 6403a56363aSOmair Javaid 641b9c1b51eSKate Stone if (error.Fail()) { 642f24741d9SOmair Javaid m_hwp_regs[i].control = tempControl; 643f24741d9SOmair Javaid m_hwp_regs[i].address = tempAddr; 644f24741d9SOmair Javaid 6453a56363aSOmair Javaid return error; 646ea8c25a8SOmair Javaid } 647ea8c25a8SOmair Javaid } 648f24741d9SOmair Javaid } 649ea8c25a8SOmair Javaid 650ea8c25a8SOmair Javaid return Error(); 651ea8c25a8SOmair Javaid } 652ea8c25a8SOmair Javaid 653ea8c25a8SOmair Javaid uint32_t 654b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) { 655ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 656ea8c25a8SOmair Javaid 657ea8c25a8SOmair Javaid if (log) 658ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 659b9c1b51eSKate Stone switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) { 660ea8c25a8SOmair Javaid case 0x01: 661ea8c25a8SOmair Javaid return 1; 662ea8c25a8SOmair Javaid case 0x03: 663ea8c25a8SOmair Javaid return 2; 664ea8c25a8SOmair Javaid case 0x0f: 665ea8c25a8SOmair Javaid return 4; 666ea8c25a8SOmair Javaid case 0xff: 667ea8c25a8SOmair Javaid return 8; 668ea8c25a8SOmair Javaid default: 669ea8c25a8SOmair Javaid return 0; 670ea8c25a8SOmair Javaid } 671ea8c25a8SOmair Javaid } 672b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) { 673ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 674ea8c25a8SOmair Javaid 675ea8c25a8SOmair Javaid if (log) 676ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 677ea8c25a8SOmair Javaid 678ea8c25a8SOmair Javaid if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 679ea8c25a8SOmair Javaid return true; 680ea8c25a8SOmair Javaid else 681ea8c25a8SOmair Javaid return false; 682ea8c25a8SOmair Javaid } 683ea8c25a8SOmair Javaid 684b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::GetWatchpointHitIndex( 685b9c1b51eSKate Stone uint32_t &wp_index, lldb::addr_t trap_addr) { 686ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 687ea8c25a8SOmair Javaid 688ea8c25a8SOmair Javaid if (log) 689ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 690ea8c25a8SOmair Javaid 691ea8c25a8SOmair Javaid uint32_t watch_size; 692ea8c25a8SOmair Javaid lldb::addr_t watch_addr; 693ea8c25a8SOmair Javaid 694b9c1b51eSKate Stone for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { 695ea8c25a8SOmair Javaid watch_size = GetWatchpointSize(wp_index); 696ea8c25a8SOmair Javaid watch_addr = m_hwp_regs[wp_index].address; 697ea8c25a8SOmair Javaid 698*05ac4c44SOmair Javaid if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && 699*05ac4c44SOmair Javaid trap_addr < watch_addr + watch_size) { 70043507f57SOmair Javaid m_hwp_regs[wp_index].hit_addr = trap_addr; 701ea8c25a8SOmair Javaid return Error(); 702ea8c25a8SOmair Javaid } 703ea8c25a8SOmair Javaid } 704ea8c25a8SOmair Javaid 705ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 706ea8c25a8SOmair Javaid return Error(); 707ea8c25a8SOmair Javaid } 708ea8c25a8SOmair Javaid 709ea8c25a8SOmair Javaid lldb::addr_t 710b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointAddress(uint32_t wp_index) { 711ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 712ea8c25a8SOmair Javaid 713ea8c25a8SOmair Javaid if (log) 714ea8c25a8SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 715ea8c25a8SOmair Javaid 716ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 717ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 718ea8c25a8SOmair Javaid 719ea8c25a8SOmair Javaid if (WatchpointIsEnabled(wp_index)) 72043507f57SOmair Javaid return m_hwp_regs[wp_index].real_addr; 72143507f57SOmair Javaid else 72243507f57SOmair Javaid return LLDB_INVALID_ADDRESS; 72343507f57SOmair Javaid } 72443507f57SOmair Javaid 72543507f57SOmair Javaid lldb::addr_t 726b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointHitAddress(uint32_t wp_index) { 72743507f57SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 72843507f57SOmair Javaid 72943507f57SOmair Javaid if (log) 73043507f57SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 73143507f57SOmair Javaid 73243507f57SOmair Javaid if (wp_index >= m_max_hwp_supported) 73343507f57SOmair Javaid return LLDB_INVALID_ADDRESS; 73443507f57SOmair Javaid 73543507f57SOmair Javaid if (WatchpointIsEnabled(wp_index)) 73643507f57SOmair Javaid return m_hwp_regs[wp_index].hit_addr; 737ea8c25a8SOmair Javaid else 738ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 739ea8c25a8SOmair Javaid } 740ea8c25a8SOmair Javaid 741b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { 742b9c1b51eSKate Stone if (!m_refresh_hwdebug_info) { 7431fd2a8cfSOmair Javaid return Error(); 7441fd2a8cfSOmair Javaid } 7451fd2a8cfSOmair Javaid 746c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 747ea8c25a8SOmair Javaid 748c7512fdcSPavel Labath int regset = NT_ARM_HW_WATCH; 749c7512fdcSPavel Labath struct iovec ioVec; 750c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 751c7512fdcSPavel Labath Error error; 752c7512fdcSPavel Labath 753c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 754c7512fdcSPavel Labath ioVec.iov_len = sizeof(dreg_state); 755b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 756b9c1b51eSKate Stone &ioVec, ioVec.iov_len); 7573a56363aSOmair Javaid 7583a56363aSOmair Javaid if (error.Fail()) 7593a56363aSOmair Javaid return error; 7603a56363aSOmair Javaid 7611fd2a8cfSOmair Javaid m_max_hwp_supported = dreg_state.dbg_info & 0xff; 762c7512fdcSPavel Labath 763c7512fdcSPavel Labath regset = NT_ARM_HW_BREAK; 764b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 765b9c1b51eSKate Stone &ioVec, ioVec.iov_len); 7661fd2a8cfSOmair Javaid 7673a56363aSOmair Javaid if (error.Fail()) 7683a56363aSOmair Javaid return error; 7693a56363aSOmair Javaid 7703a56363aSOmair Javaid m_max_hbp_supported = dreg_state.dbg_info & 0xff; 7711fd2a8cfSOmair Javaid m_refresh_hwdebug_info = false; 772c7512fdcSPavel Labath 773c7512fdcSPavel Labath return error; 774ea8c25a8SOmair Javaid } 775068f8a7eSTamas Berghammer 776b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) { 777c7512fdcSPavel Labath struct iovec ioVec; 778c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 779c7512fdcSPavel Labath Error error; 780c7512fdcSPavel Labath 781c7512fdcSPavel Labath memset(&dreg_state, 0, sizeof(dreg_state)); 782c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 783c7512fdcSPavel Labath 784b9c1b51eSKate Stone if (hwbType == eDREGTypeWATCH) { 7851fd2a8cfSOmair Javaid hwbType = NT_ARM_HW_WATCH; 786b9c1b51eSKate Stone ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + 787b9c1b51eSKate Stone (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported); 7881fd2a8cfSOmair Javaid 789b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 7901fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; 7911fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; 7921fd2a8cfSOmair Javaid } 793b9c1b51eSKate Stone } else { 7941fd2a8cfSOmair Javaid hwbType = NT_ARM_HW_BREAK; 795b9c1b51eSKate Stone ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + 796b9c1b51eSKate Stone (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported); 7971fd2a8cfSOmair Javaid 798b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 7991fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address; 8001fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control; 8011fd2a8cfSOmair Javaid } 802068f8a7eSTamas Berghammer } 803068f8a7eSTamas Berghammer 804b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), 805b9c1b51eSKate Stone &hwbType, &ioVec, ioVec.iov_len); 806c7512fdcSPavel Labath } 807c7512fdcSPavel Labath 808b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadRegisterValue( 809b9c1b51eSKate Stone uint32_t offset, const char *reg_name, uint32_t size, 810b9c1b51eSKate Stone RegisterValue &value) { 811c7512fdcSPavel Labath Error error; 812b9c1b51eSKate Stone if (offset > sizeof(struct user_pt_regs)) { 813c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 814b9c1b51eSKate Stone if (offset > sizeof(struct user_fpsimd_state)) { 815c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 816c7512fdcSPavel Labath return error; 817c7512fdcSPavel Labath } 818c7512fdcSPavel Labath elf_fpregset_t regs; 819c7512fdcSPavel Labath int regset = NT_FPREGSET; 820c7512fdcSPavel Labath struct iovec ioVec; 821c7512fdcSPavel Labath 822c7512fdcSPavel Labath ioVec.iov_base = ®s; 823c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 8244a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 8254a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 826b9c1b51eSKate Stone if (error.Success()) { 827c7512fdcSPavel Labath ArchSpec arch; 828c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 829b9c1b51eSKate Stone value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, 830b9c1b51eSKate Stone arch.GetByteOrder()); 831c7512fdcSPavel Labath else 832c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 833c7512fdcSPavel Labath } 834b9c1b51eSKate Stone } else { 835c7512fdcSPavel Labath elf_gregset_t regs; 836c7512fdcSPavel Labath int regset = NT_PRSTATUS; 837c7512fdcSPavel Labath struct iovec ioVec; 838c7512fdcSPavel Labath 839c7512fdcSPavel Labath ioVec.iov_base = ®s; 840c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 8414a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 8424a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 843b9c1b51eSKate Stone if (error.Success()) { 844c7512fdcSPavel Labath ArchSpec arch; 845c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 846b9c1b51eSKate Stone value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, 847b9c1b51eSKate Stone arch.GetByteOrder()); 848c7512fdcSPavel Labath else 849c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 850c7512fdcSPavel Labath } 851c7512fdcSPavel Labath } 852c7512fdcSPavel Labath return error; 853068f8a7eSTamas Berghammer } 854068f8a7eSTamas Berghammer 855b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteRegisterValue( 856b9c1b51eSKate Stone uint32_t offset, const char *reg_name, const RegisterValue &value) { 857c7512fdcSPavel Labath Error error; 858c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 859b9c1b51eSKate Stone if (offset > sizeof(struct user_pt_regs)) { 860c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 861b9c1b51eSKate Stone if (offset > sizeof(struct user_fpsimd_state)) { 862c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 863c7512fdcSPavel Labath return error; 864c7512fdcSPavel Labath } 865c7512fdcSPavel Labath elf_fpregset_t regs; 866c7512fdcSPavel Labath int regset = NT_FPREGSET; 867c7512fdcSPavel Labath struct iovec ioVec; 868c7512fdcSPavel Labath 869c7512fdcSPavel Labath ioVec.iov_base = ®s; 870c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 871b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 872b9c1b51eSKate Stone &ioVec, sizeof regs); 873c7512fdcSPavel Labath 874b9c1b51eSKate Stone if (error.Success()) { 875b9c1b51eSKate Stone ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 876b9c1b51eSKate Stone 16); 877b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, 878b9c1b51eSKate Stone &ioVec, sizeof regs); 879c7512fdcSPavel Labath } 880b9c1b51eSKate Stone } else { 881c7512fdcSPavel Labath elf_gregset_t regs; 882c7512fdcSPavel Labath int regset = NT_PRSTATUS; 883c7512fdcSPavel Labath struct iovec ioVec; 884c7512fdcSPavel Labath 885c7512fdcSPavel Labath ioVec.iov_base = ®s; 886c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 887b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 888b9c1b51eSKate Stone &ioVec, sizeof regs); 889b9c1b51eSKate Stone if (error.Success()) { 890b9c1b51eSKate Stone ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 891b9c1b51eSKate Stone 8); 892b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, 893b9c1b51eSKate Stone &ioVec, sizeof regs); 894c7512fdcSPavel Labath } 895c7512fdcSPavel Labath } 896c7512fdcSPavel Labath return error; 897068f8a7eSTamas Berghammer } 898068f8a7eSTamas Berghammer 899b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) { 900c7512fdcSPavel Labath int regset = NT_PRSTATUS; 901c7512fdcSPavel Labath struct iovec ioVec; 902c7512fdcSPavel Labath Error error; 903c7512fdcSPavel Labath 904c7512fdcSPavel Labath ioVec.iov_base = buf; 905c7512fdcSPavel Labath ioVec.iov_len = buf_size; 906b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), 907b9c1b51eSKate Stone ®set, &ioVec, buf_size); 908068f8a7eSTamas Berghammer } 909068f8a7eSTamas Berghammer 910b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) { 911c7512fdcSPavel Labath int regset = NT_PRSTATUS; 912c7512fdcSPavel Labath struct iovec ioVec; 913c7512fdcSPavel Labath Error error; 914c7512fdcSPavel Labath 915c7512fdcSPavel Labath ioVec.iov_base = buf; 916c7512fdcSPavel Labath ioVec.iov_len = buf_size; 917b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), 918b9c1b51eSKate Stone ®set, &ioVec, buf_size); 919068f8a7eSTamas Berghammer } 920068f8a7eSTamas Berghammer 921b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) { 922c7512fdcSPavel Labath int regset = NT_FPREGSET; 923c7512fdcSPavel Labath struct iovec ioVec; 924c7512fdcSPavel Labath Error error; 925c7512fdcSPavel Labath 926c7512fdcSPavel Labath ioVec.iov_base = buf; 927c7512fdcSPavel Labath ioVec.iov_len = buf_size; 928b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), 929b9c1b51eSKate Stone ®set, &ioVec, buf_size); 930068f8a7eSTamas Berghammer } 931068f8a7eSTamas Berghammer 932b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) { 933c7512fdcSPavel Labath int regset = NT_FPREGSET; 934c7512fdcSPavel Labath struct iovec ioVec; 935c7512fdcSPavel Labath Error error; 936c7512fdcSPavel Labath 937c7512fdcSPavel Labath ioVec.iov_base = buf; 938c7512fdcSPavel Labath ioVec.iov_len = buf_size; 939b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), 940b9c1b51eSKate Stone ®set, &ioVec, buf_size); 941068f8a7eSTamas Berghammer } 942068f8a7eSTamas Berghammer 943b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset( 944b9c1b51eSKate Stone const RegisterInfo *reg_info) const { 945b9c1b51eSKate Stone return reg_info->byte_offset - 946b9c1b51eSKate Stone GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; 947c40e7b17STamas Berghammer } 948c40e7b17STamas Berghammer 949068f8a7eSTamas Berghammer #endif // defined (__arm64__) || defined (__aarch64__) 950