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 12*e85e6021STamas 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" 27*e85e6021STamas Berghammer #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 28068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" 29068f8a7eSTamas Berghammer 30068f8a7eSTamas Berghammer // System includes - They have to be included after framework includes because they define some 31068f8a7eSTamas Berghammer // macros which collide with variable names in other modules 32068f8a7eSTamas Berghammer #include <sys/socket.h> 33068f8a7eSTamas Berghammer // NT_PRSTATUS and NT_FPREGSET definition 34068f8a7eSTamas Berghammer #include <elf.h> 35068f8a7eSTamas Berghammer 36068f8a7eSTamas Berghammer #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) 371e209fccSTamas Berghammer 381e209fccSTamas Berghammer using namespace lldb; 391e209fccSTamas Berghammer using namespace lldb_private; 40db264a6dSTamas Berghammer using namespace lldb_private::process_linux; 411e209fccSTamas Berghammer 421e209fccSTamas Berghammer // ARM64 general purpose registers. 431e209fccSTamas Berghammer static const uint32_t g_gpr_regnums_arm64[] = 441e209fccSTamas Berghammer { 451e209fccSTamas Berghammer gpr_x0_arm64, 461e209fccSTamas Berghammer gpr_x1_arm64, 471e209fccSTamas Berghammer gpr_x2_arm64, 481e209fccSTamas Berghammer gpr_x3_arm64, 491e209fccSTamas Berghammer gpr_x4_arm64, 501e209fccSTamas Berghammer gpr_x5_arm64, 511e209fccSTamas Berghammer gpr_x6_arm64, 521e209fccSTamas Berghammer gpr_x7_arm64, 531e209fccSTamas Berghammer gpr_x8_arm64, 541e209fccSTamas Berghammer gpr_x9_arm64, 551e209fccSTamas Berghammer gpr_x10_arm64, 561e209fccSTamas Berghammer gpr_x11_arm64, 571e209fccSTamas Berghammer gpr_x12_arm64, 581e209fccSTamas Berghammer gpr_x13_arm64, 591e209fccSTamas Berghammer gpr_x14_arm64, 601e209fccSTamas Berghammer gpr_x15_arm64, 611e209fccSTamas Berghammer gpr_x16_arm64, 621e209fccSTamas Berghammer gpr_x17_arm64, 631e209fccSTamas Berghammer gpr_x18_arm64, 641e209fccSTamas Berghammer gpr_x19_arm64, 651e209fccSTamas Berghammer gpr_x20_arm64, 661e209fccSTamas Berghammer gpr_x21_arm64, 671e209fccSTamas Berghammer gpr_x22_arm64, 681e209fccSTamas Berghammer gpr_x23_arm64, 691e209fccSTamas Berghammer gpr_x24_arm64, 701e209fccSTamas Berghammer gpr_x25_arm64, 711e209fccSTamas Berghammer gpr_x26_arm64, 721e209fccSTamas Berghammer gpr_x27_arm64, 731e209fccSTamas Berghammer gpr_x28_arm64, 741e209fccSTamas Berghammer gpr_fp_arm64, 751e209fccSTamas Berghammer gpr_lr_arm64, 761e209fccSTamas Berghammer gpr_sp_arm64, 771e209fccSTamas Berghammer gpr_pc_arm64, 781e209fccSTamas Berghammer gpr_cpsr_arm64, 791e209fccSTamas Berghammer LLDB_INVALID_REGNUM // register sets need to end with this flag 801e209fccSTamas Berghammer }; 811e209fccSTamas Berghammer static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \ 821e209fccSTamas Berghammer "g_gpr_regnums_arm64 has wrong number of register infos"); 831e209fccSTamas Berghammer 841e209fccSTamas Berghammer // ARM64 floating point registers. 851e209fccSTamas Berghammer static const uint32_t g_fpu_regnums_arm64[] = 861e209fccSTamas Berghammer { 871e209fccSTamas Berghammer fpu_v0_arm64, 881e209fccSTamas Berghammer fpu_v1_arm64, 891e209fccSTamas Berghammer fpu_v2_arm64, 901e209fccSTamas Berghammer fpu_v3_arm64, 911e209fccSTamas Berghammer fpu_v4_arm64, 921e209fccSTamas Berghammer fpu_v5_arm64, 931e209fccSTamas Berghammer fpu_v6_arm64, 941e209fccSTamas Berghammer fpu_v7_arm64, 951e209fccSTamas Berghammer fpu_v8_arm64, 961e209fccSTamas Berghammer fpu_v9_arm64, 971e209fccSTamas Berghammer fpu_v10_arm64, 981e209fccSTamas Berghammer fpu_v11_arm64, 991e209fccSTamas Berghammer fpu_v12_arm64, 1001e209fccSTamas Berghammer fpu_v13_arm64, 1011e209fccSTamas Berghammer fpu_v14_arm64, 1021e209fccSTamas Berghammer fpu_v15_arm64, 1031e209fccSTamas Berghammer fpu_v16_arm64, 1041e209fccSTamas Berghammer fpu_v17_arm64, 1051e209fccSTamas Berghammer fpu_v18_arm64, 1061e209fccSTamas Berghammer fpu_v19_arm64, 1071e209fccSTamas Berghammer fpu_v20_arm64, 1081e209fccSTamas Berghammer fpu_v21_arm64, 1091e209fccSTamas Berghammer fpu_v22_arm64, 1101e209fccSTamas Berghammer fpu_v23_arm64, 1111e209fccSTamas Berghammer fpu_v24_arm64, 1121e209fccSTamas Berghammer fpu_v25_arm64, 1131e209fccSTamas Berghammer fpu_v26_arm64, 1141e209fccSTamas Berghammer fpu_v27_arm64, 1151e209fccSTamas Berghammer fpu_v28_arm64, 1161e209fccSTamas Berghammer fpu_v29_arm64, 1171e209fccSTamas Berghammer fpu_v30_arm64, 1181e209fccSTamas Berghammer fpu_v31_arm64, 1191e209fccSTamas Berghammer fpu_fpsr_arm64, 1201e209fccSTamas Berghammer fpu_fpcr_arm64, 1211e209fccSTamas Berghammer LLDB_INVALID_REGNUM // register sets need to end with this flag 1221e209fccSTamas Berghammer }; 1231e209fccSTamas Berghammer static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \ 1241e209fccSTamas Berghammer "g_fpu_regnums_arm64 has wrong number of register infos"); 1251e209fccSTamas Berghammer 1261e209fccSTamas Berghammer namespace { 1271e209fccSTamas Berghammer // Number of register sets provided by this context. 1281e209fccSTamas Berghammer enum 1291e209fccSTamas Berghammer { 1301e209fccSTamas Berghammer k_num_register_sets = 2 1311e209fccSTamas Berghammer }; 1321e209fccSTamas Berghammer } 1331e209fccSTamas Berghammer 1341e209fccSTamas Berghammer // Register sets for ARM64. 135db264a6dSTamas Berghammer static const RegisterSet 1361e209fccSTamas Berghammer g_reg_sets_arm64[k_num_register_sets] = 1371e209fccSTamas Berghammer { 1381e209fccSTamas Berghammer { "General Purpose Registers", "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 }, 1391e209fccSTamas Berghammer { "Floating Point Registers", "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 } 1401e209fccSTamas Berghammer }; 1411e209fccSTamas Berghammer 142068f8a7eSTamas Berghammer NativeRegisterContextLinux* 143068f8a7eSTamas Berghammer NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch, 144068f8a7eSTamas Berghammer NativeThreadProtocol &native_thread, 145068f8a7eSTamas Berghammer uint32_t concrete_frame_idx) 146068f8a7eSTamas Berghammer { 147*e85e6021STamas Berghammer Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS); 148*e85e6021STamas Berghammer switch (target_arch.GetMachine()) 149*e85e6021STamas Berghammer { 150*e85e6021STamas Berghammer case llvm::Triple::arm: 151*e85e6021STamas Berghammer return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx); 152*e85e6021STamas Berghammer case llvm::Triple::aarch64: 153068f8a7eSTamas Berghammer return new NativeRegisterContextLinux_arm64(target_arch, native_thread, concrete_frame_idx); 154*e85e6021STamas Berghammer default: 155*e85e6021STamas Berghammer if (log) 156*e85e6021STamas Berghammer log->Printf("NativeRegisterContextLinux::%s() have no register context for architecture: %s\n", __FUNCTION__, 157*e85e6021STamas Berghammer target_arch.GetTriple().getArchName().str().c_str()); 158*e85e6021STamas Berghammer return nullptr; 159*e85e6021STamas Berghammer } 160068f8a7eSTamas Berghammer } 161068f8a7eSTamas Berghammer 162068f8a7eSTamas Berghammer NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (const ArchSpec& target_arch, 163068f8a7eSTamas Berghammer NativeThreadProtocol &native_thread, 164068f8a7eSTamas Berghammer uint32_t concrete_frame_idx) : 165068f8a7eSTamas Berghammer NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm64(target_arch)) 166068f8a7eSTamas Berghammer { 167068f8a7eSTamas Berghammer switch (target_arch.GetMachine()) 1681e209fccSTamas Berghammer { 1691e209fccSTamas Berghammer case llvm::Triple::aarch64: 1701e209fccSTamas Berghammer m_reg_info.num_registers = k_num_registers_arm64; 1711e209fccSTamas Berghammer m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64; 1721e209fccSTamas Berghammer m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64; 1731e209fccSTamas Berghammer m_reg_info.last_gpr = k_last_gpr_arm64; 1741e209fccSTamas Berghammer m_reg_info.first_fpr = k_first_fpr_arm64; 1751e209fccSTamas Berghammer m_reg_info.last_fpr = k_last_fpr_arm64; 1761e209fccSTamas Berghammer m_reg_info.first_fpr_v = fpu_v0_arm64; 1771e209fccSTamas Berghammer m_reg_info.last_fpr_v = fpu_v31_arm64; 1781e209fccSTamas Berghammer m_reg_info.gpr_flags = gpr_cpsr_arm64; 1791e209fccSTamas Berghammer break; 1801e209fccSTamas Berghammer default: 1811e209fccSTamas Berghammer assert(false && "Unhandled target architecture."); 1821e209fccSTamas Berghammer break; 1831e209fccSTamas Berghammer } 1841e209fccSTamas Berghammer 1851e209fccSTamas Berghammer ::memset(&m_fpr, 0, sizeof (m_fpr)); 1861e209fccSTamas Berghammer ::memset(&m_gpr_arm64, 0, sizeof (m_gpr_arm64)); 187ea8c25a8SOmair Javaid ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs)); 188ea8c25a8SOmair Javaid 189ea8c25a8SOmair Javaid // 16 is just a maximum value, query hardware for actual watchpoint count 190ea8c25a8SOmair Javaid m_max_hwp_supported = 16; 191ea8c25a8SOmair Javaid m_max_hbp_supported = 16; 192ea8c25a8SOmair Javaid m_refresh_hwdebug_info = true; 1931e209fccSTamas Berghammer } 1941e209fccSTamas Berghammer 1951e209fccSTamas Berghammer uint32_t 1961e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetRegisterSetCount () const 1971e209fccSTamas Berghammer { 1981e209fccSTamas Berghammer return k_num_register_sets; 1991e209fccSTamas Berghammer } 2001e209fccSTamas Berghammer 201db264a6dSTamas Berghammer const RegisterSet * 2021e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetRegisterSet (uint32_t set_index) const 2031e209fccSTamas Berghammer { 2041e209fccSTamas Berghammer if (set_index < k_num_register_sets) 2051e209fccSTamas Berghammer return &g_reg_sets_arm64[set_index]; 2061e209fccSTamas Berghammer 2071e209fccSTamas Berghammer return nullptr; 2081e209fccSTamas Berghammer } 2091e209fccSTamas Berghammer 210cec93c35STamas Berghammer uint32_t 211cec93c35STamas Berghammer NativeRegisterContextLinux_arm64::GetUserRegisterCount() const 212cec93c35STamas Berghammer { 213cec93c35STamas Berghammer uint32_t count = 0; 214cec93c35STamas Berghammer for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) 215cec93c35STamas Berghammer count += g_reg_sets_arm64[set_index].num_registers; 216cec93c35STamas Berghammer return count; 217cec93c35STamas Berghammer } 218cec93c35STamas Berghammer 219db264a6dSTamas Berghammer Error 2201e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) 2211e209fccSTamas Berghammer { 2221e209fccSTamas Berghammer Error error; 2231e209fccSTamas Berghammer 2241e209fccSTamas Berghammer if (!reg_info) 2251e209fccSTamas Berghammer { 2261e209fccSTamas Berghammer error.SetErrorString ("reg_info NULL"); 2271e209fccSTamas Berghammer return error; 2281e209fccSTamas Berghammer } 2291e209fccSTamas Berghammer 2301e209fccSTamas Berghammer const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 2311e209fccSTamas Berghammer 2321e209fccSTamas Berghammer if (IsFPR(reg)) 2331e209fccSTamas Berghammer { 234068f8a7eSTamas Berghammer error = ReadFPR(); 235068f8a7eSTamas Berghammer if (error.Fail()) 2361e209fccSTamas Berghammer return error; 2371e209fccSTamas Berghammer } 2381e209fccSTamas Berghammer else 2391e209fccSTamas Berghammer { 2401e209fccSTamas Berghammer uint32_t full_reg = reg; 2411e209fccSTamas Berghammer bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 2421e209fccSTamas Berghammer 2431e209fccSTamas Berghammer if (is_subreg) 2441e209fccSTamas Berghammer { 2451e209fccSTamas Berghammer // Read the full aligned 64-bit register. 2461e209fccSTamas Berghammer full_reg = reg_info->invalidate_regs[0]; 2471e209fccSTamas Berghammer } 2481e209fccSTamas Berghammer 2491e209fccSTamas Berghammer error = ReadRegisterRaw(full_reg, reg_value); 2501e209fccSTamas Berghammer 2511e209fccSTamas Berghammer if (error.Success ()) 2521e209fccSTamas Berghammer { 2531e209fccSTamas Berghammer // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. 2541e209fccSTamas Berghammer if (is_subreg && (reg_info->byte_offset & 0x1)) 2551e209fccSTamas Berghammer reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); 2561e209fccSTamas Berghammer 2571e209fccSTamas Berghammer // If our return byte size was greater than the return value reg size, then 2581e209fccSTamas Berghammer // use the type specified by reg_info rather than the uint64_t default 2591e209fccSTamas Berghammer if (reg_value.GetByteSize() > reg_info->byte_size) 2601e209fccSTamas Berghammer reg_value.SetType(reg_info); 2611e209fccSTamas Berghammer } 2621e209fccSTamas Berghammer return error; 2631e209fccSTamas Berghammer } 2641e209fccSTamas Berghammer 2651e209fccSTamas Berghammer // Get pointer to m_fpr variable and set the data from it. 266c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 267c40e7b17STamas Berghammer assert (fpr_offset < sizeof m_fpr); 268c40e7b17STamas Berghammer uint8_t *src = (uint8_t *)&m_fpr + fpr_offset; 269cec93c35STamas Berghammer reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, eByteOrderLittle, error); 2701e209fccSTamas Berghammer 2711e209fccSTamas Berghammer return error; 2721e209fccSTamas Berghammer } 2731e209fccSTamas Berghammer 274db264a6dSTamas Berghammer Error 2751e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) 2761e209fccSTamas Berghammer { 2771e209fccSTamas Berghammer if (!reg_info) 2781e209fccSTamas Berghammer return Error ("reg_info NULL"); 2791e209fccSTamas Berghammer 2801e209fccSTamas Berghammer const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 2811e209fccSTamas Berghammer if (reg_index == LLDB_INVALID_REGNUM) 2821e209fccSTamas Berghammer return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>"); 2831e209fccSTamas Berghammer 2841e209fccSTamas Berghammer if (IsGPR(reg_index)) 2851e209fccSTamas Berghammer return WriteRegisterRaw(reg_index, reg_value); 2861e209fccSTamas Berghammer 2871e209fccSTamas Berghammer if (IsFPR(reg_index)) 2881e209fccSTamas Berghammer { 2891e209fccSTamas Berghammer // Get pointer to m_fpr variable and set the data to it. 290c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 291c40e7b17STamas Berghammer assert (fpr_offset < sizeof m_fpr); 292c40e7b17STamas Berghammer uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset; 2931e209fccSTamas Berghammer switch (reg_info->byte_size) 2941e209fccSTamas Berghammer { 2951e209fccSTamas Berghammer case 2: 2961e209fccSTamas Berghammer *(uint16_t *)dst = reg_value.GetAsUInt16(); 2971e209fccSTamas Berghammer break; 2981e209fccSTamas Berghammer case 4: 2991e209fccSTamas Berghammer *(uint32_t *)dst = reg_value.GetAsUInt32(); 3001e209fccSTamas Berghammer break; 3011e209fccSTamas Berghammer case 8: 3021e209fccSTamas Berghammer *(uint64_t *)dst = reg_value.GetAsUInt64(); 3031e209fccSTamas Berghammer break; 3041e209fccSTamas Berghammer default: 3051e209fccSTamas Berghammer assert(false && "Unhandled data size."); 3061e209fccSTamas Berghammer return Error ("unhandled register data size %" PRIu32, reg_info->byte_size); 3071e209fccSTamas Berghammer } 3081e209fccSTamas Berghammer 309068f8a7eSTamas Berghammer Error error = WriteFPR(); 310068f8a7eSTamas Berghammer if (error.Fail()) 311068f8a7eSTamas Berghammer return error; 3121e209fccSTamas Berghammer 3131e209fccSTamas Berghammer return Error (); 3141e209fccSTamas Berghammer } 3151e209fccSTamas Berghammer 3161e209fccSTamas Berghammer return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown"); 3171e209fccSTamas Berghammer } 3181e209fccSTamas Berghammer 319db264a6dSTamas Berghammer Error 3201e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) 3211e209fccSTamas Berghammer { 3221e209fccSTamas Berghammer Error error; 3231e209fccSTamas Berghammer 324db264a6dSTamas Berghammer data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); 3251e209fccSTamas Berghammer if (!data_sp) 3261e209fccSTamas Berghammer return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE); 3271e209fccSTamas Berghammer 328068f8a7eSTamas Berghammer error = ReadGPR(); 329068f8a7eSTamas Berghammer if (error.Fail()) 3301e209fccSTamas Berghammer return error; 3311e209fccSTamas Berghammer 332068f8a7eSTamas Berghammer error = ReadFPR(); 333068f8a7eSTamas Berghammer if (error.Fail()) 3341e209fccSTamas Berghammer return error; 3351e209fccSTamas Berghammer 3361e209fccSTamas Berghammer uint8_t *dst = data_sp->GetBytes (); 3371e209fccSTamas Berghammer if (dst == nullptr) 3381e209fccSTamas Berghammer { 3391e209fccSTamas Berghammer error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE); 3401e209fccSTamas Berghammer return error; 3411e209fccSTamas Berghammer } 3421e209fccSTamas Berghammer 3431e209fccSTamas Berghammer ::memcpy (dst, &m_gpr_arm64, GetGPRSize()); 3441e209fccSTamas Berghammer dst += GetGPRSize(); 3451e209fccSTamas Berghammer ::memcpy (dst, &m_fpr, sizeof(m_fpr)); 3461e209fccSTamas Berghammer 3471e209fccSTamas Berghammer return error; 3481e209fccSTamas Berghammer } 3491e209fccSTamas Berghammer 350db264a6dSTamas Berghammer Error 3511e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) 3521e209fccSTamas Berghammer { 3531e209fccSTamas Berghammer Error error; 3541e209fccSTamas Berghammer 3551e209fccSTamas Berghammer if (!data_sp) 3561e209fccSTamas Berghammer { 3571e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__); 3581e209fccSTamas Berghammer return error; 3591e209fccSTamas Berghammer } 3601e209fccSTamas Berghammer 3611e209fccSTamas Berghammer if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) 3621e209fccSTamas Berghammer { 3631e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ()); 3641e209fccSTamas Berghammer return error; 3651e209fccSTamas Berghammer } 3661e209fccSTamas Berghammer 3671e209fccSTamas Berghammer 3681e209fccSTamas Berghammer uint8_t *src = data_sp->GetBytes (); 3691e209fccSTamas Berghammer if (src == nullptr) 3701e209fccSTamas Berghammer { 3711e209fccSTamas Berghammer error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); 3721e209fccSTamas Berghammer return error; 3731e209fccSTamas Berghammer } 3741e209fccSTamas Berghammer ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ()); 3751e209fccSTamas Berghammer 376068f8a7eSTamas Berghammer error = WriteGPR(); 377068f8a7eSTamas Berghammer if (error.Fail()) 3781e209fccSTamas Berghammer return error; 3791e209fccSTamas Berghammer 3801e209fccSTamas Berghammer src += GetRegisterInfoInterface ().GetGPRSize (); 3811e209fccSTamas Berghammer ::memcpy (&m_fpr, src, sizeof(m_fpr)); 3821e209fccSTamas Berghammer 383068f8a7eSTamas Berghammer error = WriteFPR(); 3841e209fccSTamas Berghammer if (error.Fail()) 3851e209fccSTamas Berghammer return error; 3861e209fccSTamas Berghammer 3871e209fccSTamas Berghammer return error; 3881e209fccSTamas Berghammer } 3891e209fccSTamas Berghammer 3901e209fccSTamas Berghammer bool 3911e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const 3921e209fccSTamas Berghammer { 3931e209fccSTamas Berghammer return reg <= m_reg_info.last_gpr; // GPR's come first. 3941e209fccSTamas Berghammer } 3951e209fccSTamas Berghammer 3961e209fccSTamas Berghammer bool 3971e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const 3981e209fccSTamas Berghammer { 3991e209fccSTamas Berghammer return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 4001e209fccSTamas Berghammer } 4011e209fccSTamas Berghammer 402ea8c25a8SOmair Javaid uint32_t 403ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) 404ea8c25a8SOmair Javaid { 405ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 406ea8c25a8SOmair Javaid 407ea8c25a8SOmair Javaid if (log) 408ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 409ea8c25a8SOmair Javaid 4103a56363aSOmair Javaid Error error; 411ea8c25a8SOmair Javaid 4123a56363aSOmair Javaid // Read hardware breakpoint and watchpoint information. 4133a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 4143a56363aSOmair Javaid 4153a56363aSOmair Javaid if (error.Fail()) 4163a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 4173a56363aSOmair Javaid 4183a56363aSOmair Javaid uint32_t control_value = 0, bp_index = 0; 419ea8c25a8SOmair Javaid 420ea8c25a8SOmair Javaid // Check if size has a valid hardware breakpoint length. 421ea8c25a8SOmair Javaid if (size != 4) 422ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware breakpoint 423ea8c25a8SOmair Javaid 424ea8c25a8SOmair Javaid // Check 4-byte alignment for hardware breakpoint target address. 425ea8c25a8SOmair Javaid if (addr & 0x03) 426ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. 427ea8c25a8SOmair Javaid 428ea8c25a8SOmair Javaid // Setup control value 429ea8c25a8SOmair Javaid control_value = 0; 430ea8c25a8SOmair Javaid control_value |= ((1 << size) - 1) << 5; 431ea8c25a8SOmair Javaid control_value |= (2 << 1) | 1; 432ea8c25a8SOmair Javaid 433ea8c25a8SOmair Javaid // Iterate over stored hardware breakpoints 434ea8c25a8SOmair Javaid // Find a free bp_index or update reference count if duplicate. 435ea8c25a8SOmair Javaid bp_index = LLDB_INVALID_INDEX32; 436ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hbp_supported; i++) 437ea8c25a8SOmair Javaid { 438ea8c25a8SOmair Javaid if ((m_hbr_regs[i].control & 1) == 0) 439ea8c25a8SOmair Javaid { 440ea8c25a8SOmair Javaid bp_index = i; // Mark last free slot 441ea8c25a8SOmair Javaid } 442ea8c25a8SOmair Javaid else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value) 443ea8c25a8SOmair Javaid { 444ea8c25a8SOmair Javaid bp_index = i; // Mark duplicate index 445ea8c25a8SOmair Javaid break; // Stop searching here 446ea8c25a8SOmair Javaid } 447ea8c25a8SOmair Javaid } 448ea8c25a8SOmair Javaid 449ea8c25a8SOmair Javaid if (bp_index == LLDB_INVALID_INDEX32) 450ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; 451ea8c25a8SOmair Javaid 452f24741d9SOmair Javaid // Add new or update existing breakpoint 453ea8c25a8SOmair Javaid if ((m_hbr_regs[bp_index].control & 1) == 0) 454ea8c25a8SOmair Javaid { 455ea8c25a8SOmair Javaid m_hbr_regs[bp_index].address = addr; 456ea8c25a8SOmair Javaid m_hbr_regs[bp_index].control = control_value; 457ea8c25a8SOmair Javaid m_hbr_regs[bp_index].refcount = 1; 458ea8c25a8SOmair Javaid 4591fd2a8cfSOmair Javaid // PTRACE call to set corresponding hardware breakpoint register. 4603a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK); 4613a56363aSOmair Javaid 4623a56363aSOmair Javaid if (error.Fail()) 463f24741d9SOmair Javaid { 464f24741d9SOmair Javaid m_hbr_regs[bp_index].address = 0; 465f24741d9SOmair Javaid m_hbr_regs[bp_index].control &= ~1; 466f24741d9SOmair Javaid m_hbr_regs[bp_index].refcount = 0; 467f24741d9SOmair Javaid 4683a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 469ea8c25a8SOmair Javaid } 470f24741d9SOmair Javaid } 471ea8c25a8SOmair Javaid else 472ea8c25a8SOmair Javaid m_hbr_regs[bp_index].refcount++; 473ea8c25a8SOmair Javaid 474ea8c25a8SOmair Javaid return bp_index; 475ea8c25a8SOmair Javaid } 476ea8c25a8SOmair Javaid 477ea8c25a8SOmair Javaid bool 478ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx) 479ea8c25a8SOmair Javaid { 480ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 481ea8c25a8SOmair Javaid 482ea8c25a8SOmair Javaid if (log) 483ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 484ea8c25a8SOmair Javaid 4853a56363aSOmair Javaid Error error; 4863a56363aSOmair Javaid 4871fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 4883a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 4893a56363aSOmair Javaid 4903a56363aSOmair Javaid if (error.Fail()) 4913a56363aSOmair Javaid return false; 4921fd2a8cfSOmair Javaid 493ea8c25a8SOmair Javaid if (hw_idx >= m_max_hbp_supported) 494ea8c25a8SOmair Javaid return false; 495ea8c25a8SOmair Javaid 496ea8c25a8SOmair Javaid // Update reference count if multiple references. 497ea8c25a8SOmair Javaid if (m_hbr_regs[hw_idx].refcount > 1) 498ea8c25a8SOmair Javaid { 499ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].refcount--; 500ea8c25a8SOmair Javaid return true; 501ea8c25a8SOmair Javaid } 502ea8c25a8SOmair Javaid else if (m_hbr_regs[hw_idx].refcount == 1) 503ea8c25a8SOmair Javaid { 504f24741d9SOmair Javaid // Create a backup we can revert to in case of failure. 505f24741d9SOmair Javaid lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; 506f24741d9SOmair Javaid uint32_t tempControl = m_hbr_regs[hw_idx].control; 507f24741d9SOmair Javaid uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount; 508f24741d9SOmair Javaid 509ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].control &= ~1; 510ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].address = 0; 511ea8c25a8SOmair Javaid m_hbr_regs[hw_idx].refcount = 0; 512ea8c25a8SOmair Javaid 5131fd2a8cfSOmair Javaid // PTRACE call to clear corresponding hardware breakpoint register. 5141fd2a8cfSOmair Javaid WriteHardwareDebugRegs(eDREGTypeBREAK); 5153a56363aSOmair Javaid 5163a56363aSOmair Javaid if (error.Fail()) 517f24741d9SOmair Javaid { 518f24741d9SOmair Javaid m_hbr_regs[hw_idx].control = tempControl; 519f24741d9SOmair Javaid m_hbr_regs[hw_idx].address = tempAddr; 520f24741d9SOmair Javaid m_hbr_regs[hw_idx].refcount = tempRefCount; 521f24741d9SOmair Javaid 5223a56363aSOmair Javaid return false; 523f24741d9SOmair Javaid } 5243a56363aSOmair Javaid 5253a56363aSOmair Javaid return true; 526ea8c25a8SOmair Javaid } 527ea8c25a8SOmair Javaid 528ea8c25a8SOmair Javaid return false; 529ea8c25a8SOmair Javaid } 530ea8c25a8SOmair Javaid 531ea8c25a8SOmair Javaid uint32_t 532ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints () 533ea8c25a8SOmair Javaid { 534ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 535ea8c25a8SOmair Javaid 536ea8c25a8SOmair Javaid if (log) 537ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 538ea8c25a8SOmair Javaid 5393a56363aSOmair Javaid Error error; 5403a56363aSOmair Javaid 5411fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 5423a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 5433a56363aSOmair Javaid 5443a56363aSOmair Javaid if (error.Fail()) 5453a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 5461fd2a8cfSOmair Javaid 547ea8c25a8SOmair Javaid return m_max_hwp_supported; 548ea8c25a8SOmair Javaid } 549ea8c25a8SOmair Javaid 550ea8c25a8SOmair Javaid uint32_t 551ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) 552ea8c25a8SOmair Javaid { 553ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 554ea8c25a8SOmair Javaid 555ea8c25a8SOmair Javaid if (log) 556ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 557ea8c25a8SOmair Javaid 5583a56363aSOmair Javaid Error error; 559ea8c25a8SOmair Javaid 5603a56363aSOmair Javaid // Read hardware breakpoint and watchpoint information. 5613a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 5623a56363aSOmair Javaid 5633a56363aSOmair Javaid if (error.Fail()) 5643a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 5653a56363aSOmair Javaid 5663a56363aSOmair Javaid uint32_t control_value = 0, wp_index = 0; 567ea8c25a8SOmair Javaid 5681fd2a8cfSOmair Javaid // Check if we are setting watchpoint other than read/write/access 5691fd2a8cfSOmair Javaid // Also update watchpoint flag to match AArch64 write-read bit configuration. 5701fd2a8cfSOmair Javaid switch (watch_flags) 5711fd2a8cfSOmair Javaid { 5721fd2a8cfSOmair Javaid case 1: 5731fd2a8cfSOmair Javaid watch_flags = 2; 5741fd2a8cfSOmair Javaid break; 5751fd2a8cfSOmair Javaid case 2: 5761fd2a8cfSOmair Javaid watch_flags = 1; 5771fd2a8cfSOmair Javaid break; 5781fd2a8cfSOmair Javaid case 3: 5791fd2a8cfSOmair Javaid break; 5801fd2a8cfSOmair Javaid default: 5811fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 5821fd2a8cfSOmair Javaid } 583ea8c25a8SOmair Javaid 584ea8c25a8SOmair Javaid // Check if size has a valid hardware watchpoint length. 585ea8c25a8SOmair Javaid if (size != 1 && size != 2 && size != 4 && size != 8) 5861fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 587ea8c25a8SOmair Javaid 588ea8c25a8SOmair Javaid // Check 8-byte alignment for hardware watchpoint target address. 589ea8c25a8SOmair Javaid // TODO: Add support for watching un-aligned addresses 590ea8c25a8SOmair Javaid if (addr & 0x07) 5911fd2a8cfSOmair Javaid return LLDB_INVALID_INDEX32; 592ea8c25a8SOmair Javaid 593ea8c25a8SOmair Javaid // Setup control value 594ea8c25a8SOmair Javaid control_value = watch_flags << 3; 595ea8c25a8SOmair Javaid control_value |= ((1 << size) - 1) << 5; 596ea8c25a8SOmair Javaid control_value |= (2 << 1) | 1; 597ea8c25a8SOmair Javaid 598ea8c25a8SOmair Javaid // Iterate over stored watchpoints 599ea8c25a8SOmair Javaid // Find a free wp_index or update reference count if duplicate. 600ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 601ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 602ea8c25a8SOmair Javaid { 603ea8c25a8SOmair Javaid if ((m_hwp_regs[i].control & 1) == 0) 604ea8c25a8SOmair Javaid { 605ea8c25a8SOmair Javaid wp_index = i; // Mark last free slot 606ea8c25a8SOmair Javaid } 607ea8c25a8SOmair Javaid else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value) 608ea8c25a8SOmair Javaid { 609ea8c25a8SOmair Javaid wp_index = i; // Mark duplicate index 610ea8c25a8SOmair Javaid break; // Stop searching here 611ea8c25a8SOmair Javaid } 612ea8c25a8SOmair Javaid } 613ea8c25a8SOmair Javaid 614ea8c25a8SOmair Javaid if (wp_index == LLDB_INVALID_INDEX32) 615ea8c25a8SOmair Javaid return LLDB_INVALID_INDEX32; 616ea8c25a8SOmair Javaid 617ea8c25a8SOmair Javaid // Add new or update existing watchpoint 618ea8c25a8SOmair Javaid if ((m_hwp_regs[wp_index].control & 1) == 0) 619ea8c25a8SOmair Javaid { 6201fd2a8cfSOmair Javaid // Update watchpoint in local cache 621ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = addr; 622ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control = control_value; 623ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount = 1; 624ea8c25a8SOmair Javaid 625ea8c25a8SOmair Javaid // PTRACE call to set corresponding watchpoint register. 6263a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 6273a56363aSOmair Javaid 6283a56363aSOmair Javaid if (error.Fail()) 629f24741d9SOmair Javaid { 630f24741d9SOmair Javaid m_hwp_regs[wp_index].address = 0; 631f24741d9SOmair Javaid m_hwp_regs[wp_index].control &= ~1; 632f24741d9SOmair Javaid m_hwp_regs[wp_index].refcount = 0; 633f24741d9SOmair Javaid 6343a56363aSOmair Javaid return LLDB_INVALID_INDEX32; 635ea8c25a8SOmair Javaid } 636f24741d9SOmair Javaid } 637ea8c25a8SOmair Javaid else 638ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount++; 639ea8c25a8SOmair Javaid 640ea8c25a8SOmair Javaid return wp_index; 641ea8c25a8SOmair Javaid } 642ea8c25a8SOmair Javaid 643ea8c25a8SOmair Javaid bool 644ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index) 645ea8c25a8SOmair Javaid { 646ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 647ea8c25a8SOmair Javaid 648ea8c25a8SOmair Javaid if (log) 649ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 650ea8c25a8SOmair Javaid 6513a56363aSOmair Javaid Error error; 6523a56363aSOmair Javaid 6531fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 6543a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 6553a56363aSOmair Javaid 6563a56363aSOmair Javaid if (error.Fail()) 6573a56363aSOmair Javaid return false; 658ea8c25a8SOmair Javaid 659ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 660ea8c25a8SOmair Javaid return false; 661ea8c25a8SOmair Javaid 662ea8c25a8SOmair Javaid // Update reference count if multiple references. 663ea8c25a8SOmair Javaid if (m_hwp_regs[wp_index].refcount > 1) 664ea8c25a8SOmair Javaid { 665ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount--; 666ea8c25a8SOmair Javaid return true; 667ea8c25a8SOmair Javaid } 668ea8c25a8SOmair Javaid else if (m_hwp_regs[wp_index].refcount == 1) 669ea8c25a8SOmair Javaid { 670f24741d9SOmair Javaid // Create a backup we can revert to in case of failure. 671f24741d9SOmair Javaid lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 672f24741d9SOmair Javaid uint32_t tempControl = m_hwp_regs[wp_index].control; 673f24741d9SOmair Javaid uint32_t tempRefCount = m_hwp_regs[wp_index].refcount; 674f24741d9SOmair Javaid 6751fd2a8cfSOmair Javaid // Update watchpoint in local cache 676ea8c25a8SOmair Javaid m_hwp_regs[wp_index].control &= ~1; 677ea8c25a8SOmair Javaid m_hwp_regs[wp_index].address = 0; 678ea8c25a8SOmair Javaid m_hwp_regs[wp_index].refcount = 0; 679ea8c25a8SOmair Javaid 6801fd2a8cfSOmair Javaid // Ptrace call to update hardware debug registers 6813a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 6823a56363aSOmair Javaid 6833a56363aSOmair Javaid if (error.Fail()) 684f24741d9SOmair Javaid { 685f24741d9SOmair Javaid m_hwp_regs[wp_index].control = tempControl; 686f24741d9SOmair Javaid m_hwp_regs[wp_index].address = tempAddr; 687f24741d9SOmair Javaid m_hwp_regs[wp_index].refcount = tempRefCount; 688f24741d9SOmair Javaid 6893a56363aSOmair Javaid return false; 690f24741d9SOmair Javaid } 6913a56363aSOmair Javaid 692ea8c25a8SOmair Javaid return true; 693ea8c25a8SOmair Javaid } 694ea8c25a8SOmair Javaid 695ea8c25a8SOmair Javaid return false; 696ea8c25a8SOmair Javaid } 697ea8c25a8SOmair Javaid 698ea8c25a8SOmair Javaid Error 699ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints () 700ea8c25a8SOmair Javaid { 701ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 702ea8c25a8SOmair Javaid 703ea8c25a8SOmair Javaid if (log) 704ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 705ea8c25a8SOmair Javaid 7063a56363aSOmair Javaid Error error; 7073a56363aSOmair Javaid 7081fd2a8cfSOmair Javaid // Read hardware breakpoint and watchpoint information. 7093a56363aSOmair Javaid error = ReadHardwareDebugInfo (); 7103a56363aSOmair Javaid 7113a56363aSOmair Javaid if (error.Fail()) 7123a56363aSOmair Javaid return error; 713ea8c25a8SOmair Javaid 714f24741d9SOmair Javaid lldb::addr_t tempAddr = 0; 715f24741d9SOmair Javaid uint32_t tempControl = 0, tempRefCount = 0; 716f24741d9SOmair Javaid 717ea8c25a8SOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 718ea8c25a8SOmair Javaid { 719ea8c25a8SOmair Javaid if (m_hwp_regs[i].control & 0x01) 720ea8c25a8SOmair Javaid { 721f24741d9SOmair Javaid // Create a backup we can revert to in case of failure. 722f24741d9SOmair Javaid tempAddr = m_hwp_regs[i].address; 723f24741d9SOmair Javaid tempControl = m_hwp_regs[i].control; 724f24741d9SOmair Javaid tempRefCount = m_hwp_regs[i].refcount; 725f24741d9SOmair Javaid 7261fd2a8cfSOmair Javaid // Clear watchpoints in local cache 727ea8c25a8SOmair Javaid m_hwp_regs[i].control &= ~1; 728ea8c25a8SOmair Javaid m_hwp_regs[i].address = 0; 729ea8c25a8SOmair Javaid m_hwp_regs[i].refcount = 0; 730ea8c25a8SOmair Javaid 7311fd2a8cfSOmair Javaid // Ptrace call to update hardware debug registers 7323a56363aSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH); 7333a56363aSOmair Javaid 7343a56363aSOmair Javaid if (error.Fail()) 735f24741d9SOmair Javaid { 736f24741d9SOmair Javaid m_hwp_regs[i].control = tempControl; 737f24741d9SOmair Javaid m_hwp_regs[i].address = tempAddr; 738f24741d9SOmair Javaid m_hwp_regs[i].refcount = tempRefCount; 739f24741d9SOmair Javaid 7403a56363aSOmair Javaid return error; 741ea8c25a8SOmair Javaid } 742ea8c25a8SOmair Javaid } 743f24741d9SOmair Javaid } 744ea8c25a8SOmair Javaid 745ea8c25a8SOmair Javaid return Error(); 746ea8c25a8SOmair Javaid } 747ea8c25a8SOmair Javaid 748ea8c25a8SOmair Javaid uint32_t 749ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) 750ea8c25a8SOmair Javaid { 751ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 752ea8c25a8SOmair Javaid 753ea8c25a8SOmair Javaid if (log) 754ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 755ea8c25a8SOmair Javaid switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) 756ea8c25a8SOmair Javaid { 757ea8c25a8SOmair Javaid case 0x01: 758ea8c25a8SOmair Javaid return 1; 759ea8c25a8SOmair Javaid case 0x03: 760ea8c25a8SOmair Javaid return 2; 761ea8c25a8SOmair Javaid case 0x0f: 762ea8c25a8SOmair Javaid return 4; 763ea8c25a8SOmair Javaid case 0xff: 764ea8c25a8SOmair Javaid return 8; 765ea8c25a8SOmair Javaid default: 766ea8c25a8SOmair Javaid return 0; 767ea8c25a8SOmair Javaid } 768ea8c25a8SOmair Javaid } 769ea8c25a8SOmair Javaid bool 770ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) 771ea8c25a8SOmair Javaid { 772ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 773ea8c25a8SOmair Javaid 774ea8c25a8SOmair Javaid if (log) 775ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 776ea8c25a8SOmair Javaid 777ea8c25a8SOmair Javaid if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 778ea8c25a8SOmair Javaid return true; 779ea8c25a8SOmair Javaid else 780ea8c25a8SOmair Javaid return false; 781ea8c25a8SOmair Javaid } 782ea8c25a8SOmair Javaid 783ea8c25a8SOmair Javaid Error 784ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) 785ea8c25a8SOmair Javaid { 786ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 787ea8c25a8SOmair Javaid 788ea8c25a8SOmair Javaid if (log) 789ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 790ea8c25a8SOmair Javaid 791ea8c25a8SOmair Javaid uint32_t watch_size; 792ea8c25a8SOmair Javaid lldb::addr_t watch_addr; 793ea8c25a8SOmair Javaid 794ea8c25a8SOmair Javaid for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) 795ea8c25a8SOmair Javaid { 796ea8c25a8SOmair Javaid watch_size = GetWatchpointSize (wp_index); 797ea8c25a8SOmair Javaid watch_addr = m_hwp_regs[wp_index].address; 798ea8c25a8SOmair Javaid 799ea8c25a8SOmair Javaid if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) 800ea8c25a8SOmair Javaid && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) 801ea8c25a8SOmair Javaid { 802ea8c25a8SOmair Javaid return Error(); 803ea8c25a8SOmair Javaid } 804ea8c25a8SOmair Javaid } 805ea8c25a8SOmair Javaid 806ea8c25a8SOmair Javaid wp_index = LLDB_INVALID_INDEX32; 807ea8c25a8SOmair Javaid return Error(); 808ea8c25a8SOmair Javaid } 809ea8c25a8SOmair Javaid 810ea8c25a8SOmair Javaid lldb::addr_t 811ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index) 812ea8c25a8SOmair Javaid { 813ea8c25a8SOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 814ea8c25a8SOmair Javaid 815ea8c25a8SOmair Javaid if (log) 816ea8c25a8SOmair Javaid log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 817ea8c25a8SOmair Javaid 818ea8c25a8SOmair Javaid if (wp_index >= m_max_hwp_supported) 819ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 820ea8c25a8SOmair Javaid 821ea8c25a8SOmair Javaid if (WatchpointIsEnabled(wp_index)) 822ea8c25a8SOmair Javaid return m_hwp_regs[wp_index].address; 823ea8c25a8SOmair Javaid else 824ea8c25a8SOmair Javaid return LLDB_INVALID_ADDRESS; 825ea8c25a8SOmair Javaid } 826ea8c25a8SOmair Javaid 827068f8a7eSTamas Berghammer Error 8281fd2a8cfSOmair Javaid NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() 829ea8c25a8SOmair Javaid { 8301fd2a8cfSOmair Javaid if (!m_refresh_hwdebug_info) 8311fd2a8cfSOmair Javaid { 8321fd2a8cfSOmair Javaid return Error(); 8331fd2a8cfSOmair Javaid } 8341fd2a8cfSOmair Javaid 835c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 836ea8c25a8SOmair Javaid 837c7512fdcSPavel Labath int regset = NT_ARM_HW_WATCH; 838c7512fdcSPavel Labath struct iovec ioVec; 839c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 840c7512fdcSPavel Labath Error error; 841c7512fdcSPavel Labath 842c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 843c7512fdcSPavel Labath ioVec.iov_len = sizeof (dreg_state); 8444a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 8453a56363aSOmair Javaid 8463a56363aSOmair Javaid if (error.Fail()) 8473a56363aSOmair Javaid return error; 8483a56363aSOmair Javaid 8491fd2a8cfSOmair Javaid m_max_hwp_supported = dreg_state.dbg_info & 0xff; 850c7512fdcSPavel Labath 851c7512fdcSPavel Labath regset = NT_ARM_HW_BREAK; 8524a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 8531fd2a8cfSOmair Javaid 8543a56363aSOmair Javaid if (error.Fail()) 8553a56363aSOmair Javaid return error; 8563a56363aSOmair Javaid 8573a56363aSOmair Javaid m_max_hbp_supported = dreg_state.dbg_info & 0xff; 8581fd2a8cfSOmair Javaid m_refresh_hwdebug_info = false; 859c7512fdcSPavel Labath 860c7512fdcSPavel Labath return error; 861ea8c25a8SOmair Javaid } 862068f8a7eSTamas Berghammer 863068f8a7eSTamas Berghammer Error 8641fd2a8cfSOmair Javaid NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) 865068f8a7eSTamas Berghammer { 866c7512fdcSPavel Labath struct iovec ioVec; 867c7512fdcSPavel Labath struct user_hwdebug_state dreg_state; 868c7512fdcSPavel Labath Error error; 869c7512fdcSPavel Labath 870c7512fdcSPavel Labath memset (&dreg_state, 0, sizeof (dreg_state)); 871c7512fdcSPavel Labath ioVec.iov_base = &dreg_state; 872c7512fdcSPavel Labath 8731fd2a8cfSOmair Javaid if (hwbType == eDREGTypeWATCH) 874c7512fdcSPavel Labath { 8751fd2a8cfSOmair Javaid hwbType = NT_ARM_HW_WATCH; 8765cf948d2SOmair Javaid ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad) 8775cf948d2SOmair Javaid + (sizeof (dreg_state.dbg_regs [0]) * m_max_hwp_supported); 8781fd2a8cfSOmair Javaid 8791fd2a8cfSOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 8801fd2a8cfSOmair Javaid { 8811fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; 8821fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; 8831fd2a8cfSOmair Javaid } 8841fd2a8cfSOmair Javaid } 8851fd2a8cfSOmair Javaid else 8861fd2a8cfSOmair Javaid { 8871fd2a8cfSOmair Javaid hwbType = NT_ARM_HW_BREAK; 8885cf948d2SOmair Javaid ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad) 8895cf948d2SOmair Javaid + (sizeof (dreg_state.dbg_regs [0]) * m_max_hbp_supported); 8901fd2a8cfSOmair Javaid 8911fd2a8cfSOmair Javaid for (uint32_t i = 0; i < m_max_hbp_supported; i++) 8921fd2a8cfSOmair Javaid { 8931fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address; 8941fd2a8cfSOmair Javaid dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control; 8951fd2a8cfSOmair Javaid } 896068f8a7eSTamas Berghammer } 897068f8a7eSTamas Berghammer 8981fd2a8cfSOmair Javaid return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &hwbType, &ioVec, ioVec.iov_len); 899c7512fdcSPavel Labath } 900c7512fdcSPavel Labath 901c7512fdcSPavel Labath Error 902c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset, 903068f8a7eSTamas Berghammer const char* reg_name, 904068f8a7eSTamas Berghammer uint32_t size, 905068f8a7eSTamas Berghammer RegisterValue &value) 906068f8a7eSTamas Berghammer { 907c7512fdcSPavel Labath Error error; 908c7512fdcSPavel Labath if (offset > sizeof(struct user_pt_regs)) 909c7512fdcSPavel Labath { 910c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 911c7512fdcSPavel Labath if (offset > sizeof(struct user_fpsimd_state)) 912c7512fdcSPavel Labath { 913c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 914c7512fdcSPavel Labath return error; 915c7512fdcSPavel Labath } 916c7512fdcSPavel Labath elf_fpregset_t regs; 917c7512fdcSPavel Labath int regset = NT_FPREGSET; 918c7512fdcSPavel Labath struct iovec ioVec; 919c7512fdcSPavel Labath 920c7512fdcSPavel Labath ioVec.iov_base = ®s; 921c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 9224a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 9234a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 924c7512fdcSPavel Labath if (error.Success()) 925c7512fdcSPavel Labath { 926c7512fdcSPavel Labath ArchSpec arch; 927c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 928c7512fdcSPavel Labath value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, arch.GetByteOrder()); 929c7512fdcSPavel Labath else 930c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 931c7512fdcSPavel Labath } 932c7512fdcSPavel Labath } 933c7512fdcSPavel Labath else 934c7512fdcSPavel Labath { 935c7512fdcSPavel Labath elf_gregset_t regs; 936c7512fdcSPavel Labath int regset = NT_PRSTATUS; 937c7512fdcSPavel Labath struct iovec ioVec; 938c7512fdcSPavel Labath 939c7512fdcSPavel Labath ioVec.iov_base = ®s; 940c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 9414a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( 9424a9babb2SPavel Labath PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 943c7512fdcSPavel Labath if (error.Success()) 944c7512fdcSPavel Labath { 945c7512fdcSPavel Labath ArchSpec arch; 946c7512fdcSPavel Labath if (m_thread.GetProcess()->GetArchitecture(arch)) 947c7512fdcSPavel Labath value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder()); 948c7512fdcSPavel Labath else 949c7512fdcSPavel Labath error.SetErrorString("failed to get architecture"); 950c7512fdcSPavel Labath } 951c7512fdcSPavel Labath } 952c7512fdcSPavel Labath return error; 953068f8a7eSTamas Berghammer } 954068f8a7eSTamas Berghammer 955c7512fdcSPavel Labath Error 956c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset, 957068f8a7eSTamas Berghammer const char* reg_name, 958068f8a7eSTamas Berghammer const RegisterValue &value) 959068f8a7eSTamas Berghammer { 960c7512fdcSPavel Labath Error error; 961c7512fdcSPavel Labath ::pid_t tid = m_thread.GetID(); 962c7512fdcSPavel Labath if (offset > sizeof(struct user_pt_regs)) 963c7512fdcSPavel Labath { 964c7512fdcSPavel Labath uintptr_t offset = offset - sizeof(struct user_pt_regs); 965c7512fdcSPavel Labath if (offset > sizeof(struct user_fpsimd_state)) 966c7512fdcSPavel Labath { 967c7512fdcSPavel Labath error.SetErrorString("invalid offset value"); 968c7512fdcSPavel Labath return error; 969c7512fdcSPavel Labath } 970c7512fdcSPavel Labath elf_fpregset_t regs; 971c7512fdcSPavel Labath int regset = NT_FPREGSET; 972c7512fdcSPavel Labath struct iovec ioVec; 973c7512fdcSPavel Labath 974c7512fdcSPavel Labath ioVec.iov_base = ®s; 975c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 9764a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 977c7512fdcSPavel Labath 978c7512fdcSPavel Labath if (error.Success()) 979c7512fdcSPavel Labath { 980c7512fdcSPavel Labath ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 16); 9814a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 982c7512fdcSPavel Labath } 983c7512fdcSPavel Labath } 984c7512fdcSPavel Labath else 985c7512fdcSPavel Labath { 986c7512fdcSPavel Labath elf_gregset_t regs; 987c7512fdcSPavel Labath int regset = NT_PRSTATUS; 988c7512fdcSPavel Labath struct iovec ioVec; 989c7512fdcSPavel Labath 990c7512fdcSPavel Labath ioVec.iov_base = ®s; 991c7512fdcSPavel Labath ioVec.iov_len = sizeof regs; 9924a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 993c7512fdcSPavel Labath if (error.Success()) 994c7512fdcSPavel Labath { 995c7512fdcSPavel Labath ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 8); 9964a9babb2SPavel Labath error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 997c7512fdcSPavel Labath } 998c7512fdcSPavel Labath } 999c7512fdcSPavel Labath return error; 1000068f8a7eSTamas Berghammer } 1001068f8a7eSTamas Berghammer 1002c7512fdcSPavel Labath Error 1003c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) 1004068f8a7eSTamas Berghammer { 1005c7512fdcSPavel Labath int regset = NT_PRSTATUS; 1006c7512fdcSPavel Labath struct iovec ioVec; 1007c7512fdcSPavel Labath Error error; 1008c7512fdcSPavel Labath 1009c7512fdcSPavel Labath ioVec.iov_base = buf; 1010c7512fdcSPavel Labath ioVec.iov_len = buf_size; 10114a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1012068f8a7eSTamas Berghammer } 1013068f8a7eSTamas Berghammer 1014c7512fdcSPavel Labath Error 1015c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) 1016068f8a7eSTamas Berghammer { 1017c7512fdcSPavel Labath int regset = NT_PRSTATUS; 1018c7512fdcSPavel Labath struct iovec ioVec; 1019c7512fdcSPavel Labath Error error; 1020c7512fdcSPavel Labath 1021c7512fdcSPavel Labath ioVec.iov_base = buf; 1022c7512fdcSPavel Labath ioVec.iov_len = buf_size; 10234a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1024068f8a7eSTamas Berghammer } 1025068f8a7eSTamas Berghammer 1026c7512fdcSPavel Labath Error 1027c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) 1028068f8a7eSTamas Berghammer { 1029c7512fdcSPavel Labath int regset = NT_FPREGSET; 1030c7512fdcSPavel Labath struct iovec ioVec; 1031c7512fdcSPavel Labath Error error; 1032c7512fdcSPavel Labath 1033c7512fdcSPavel Labath ioVec.iov_base = buf; 1034c7512fdcSPavel Labath ioVec.iov_len = buf_size; 10354a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1036068f8a7eSTamas Berghammer } 1037068f8a7eSTamas Berghammer 1038c7512fdcSPavel Labath Error 1039c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) 1040068f8a7eSTamas Berghammer { 1041c7512fdcSPavel Labath int regset = NT_FPREGSET; 1042c7512fdcSPavel Labath struct iovec ioVec; 1043c7512fdcSPavel Labath Error error; 1044c7512fdcSPavel Labath 1045c7512fdcSPavel Labath ioVec.iov_base = buf; 1046c7512fdcSPavel Labath ioVec.iov_len = buf_size; 10474a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1048068f8a7eSTamas Berghammer } 1049068f8a7eSTamas Berghammer 1050c40e7b17STamas Berghammer uint32_t 1051c40e7b17STamas Berghammer NativeRegisterContextLinux_arm64::CalculateFprOffset(const RegisterInfo* reg_info) const 1052c40e7b17STamas Berghammer { 1053c40e7b17STamas Berghammer return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; 1054c40e7b17STamas Berghammer } 1055c40e7b17STamas Berghammer 1056068f8a7eSTamas Berghammer #endif // defined (__arm64__) || defined (__aarch64__) 1057