13f57216cSOmair Javaid //===-- NativeRegisterContextLinux_arm.cpp --------------------*- C++ -*-===// 23f57216cSOmair Javaid // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 63f57216cSOmair Javaid // 73f57216cSOmair Javaid //===----------------------------------------------------------------------===// 83f57216cSOmair Javaid 9e85e6021STamas Berghammer #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 10068f8a7eSTamas Berghammer 113f57216cSOmair Javaid #include "NativeRegisterContextLinux_arm.h" 123f57216cSOmair Javaid 13d37349f3SPavel Labath #include "Plugins/Process/Linux/NativeProcessLinux.h" 14d37349f3SPavel Labath #include "Plugins/Process/Linux/Procfs.h" 15d37349f3SPavel Labath #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 16d37349f3SPavel Labath #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" 17666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h" 186f9e6901SZachary Turner #include "lldb/Utility/Log.h" 19d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h" 2097206d57SZachary Turner #include "lldb/Utility/Status.h" 21068f8a7eSTamas Berghammer 22e85e6021STamas Berghammer #include <elf.h> 23e85e6021STamas Berghammer #include <sys/socket.h> 24e85e6021STamas Berghammer 253f57216cSOmair Javaid #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr)) 263f57216cSOmair Javaid 27ce26b7a6STamas Berghammer #ifndef PTRACE_GETVFPREGS 28ce26b7a6STamas Berghammer #define PTRACE_GETVFPREGS 27 29ce26b7a6STamas Berghammer #define PTRACE_SETVFPREGS 28 30ce26b7a6STamas Berghammer #endif 312441aecdSOmair Javaid #ifndef PTRACE_GETHBPREGS 322441aecdSOmair Javaid #define PTRACE_GETHBPREGS 29 332441aecdSOmair Javaid #define PTRACE_SETHBPREGS 30 342441aecdSOmair Javaid #endif 352441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG3) 362441aecdSOmair Javaid #define PTRACE_TYPE_ARG3 void * 372441aecdSOmair Javaid #endif 382441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG4) 392441aecdSOmair Javaid #define PTRACE_TYPE_ARG4 void * 402441aecdSOmair Javaid #endif 412441aecdSOmair Javaid 423f57216cSOmair Javaid using namespace lldb; 433f57216cSOmair Javaid using namespace lldb_private; 443f57216cSOmair Javaid using namespace lldb_private::process_linux; 453f57216cSOmair Javaid 463f57216cSOmair Javaid // arm general purpose registers. 47b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_arm[] = { 48b9c1b51eSKate Stone gpr_r0_arm, gpr_r1_arm, gpr_r2_arm, gpr_r3_arm, gpr_r4_arm, 49b9c1b51eSKate Stone gpr_r5_arm, gpr_r6_arm, gpr_r7_arm, gpr_r8_arm, gpr_r9_arm, 50b9c1b51eSKate Stone gpr_r10_arm, gpr_r11_arm, gpr_r12_arm, gpr_sp_arm, gpr_lr_arm, 51b9c1b51eSKate Stone gpr_pc_arm, gpr_cpsr_arm, 523f57216cSOmair Javaid LLDB_INVALID_REGNUM // register sets need to end with this flag 533f57216cSOmair Javaid }; 54b9c1b51eSKate Stone static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == 55b9c1b51eSKate Stone k_num_gpr_registers_arm, 563f57216cSOmair Javaid "g_gpr_regnums_arm has wrong number of register infos"); 573f57216cSOmair Javaid 583f57216cSOmair Javaid // arm floating point registers. 59b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_arm[] = { 60b9c1b51eSKate Stone fpu_s0_arm, fpu_s1_arm, fpu_s2_arm, fpu_s3_arm, fpu_s4_arm, 61b9c1b51eSKate Stone fpu_s5_arm, fpu_s6_arm, fpu_s7_arm, fpu_s8_arm, fpu_s9_arm, 62b9c1b51eSKate Stone fpu_s10_arm, fpu_s11_arm, fpu_s12_arm, fpu_s13_arm, fpu_s14_arm, 63b9c1b51eSKate Stone fpu_s15_arm, fpu_s16_arm, fpu_s17_arm, fpu_s18_arm, fpu_s19_arm, 64b9c1b51eSKate Stone fpu_s20_arm, fpu_s21_arm, fpu_s22_arm, fpu_s23_arm, fpu_s24_arm, 65b9c1b51eSKate Stone fpu_s25_arm, fpu_s26_arm, fpu_s27_arm, fpu_s28_arm, fpu_s29_arm, 66b9c1b51eSKate Stone fpu_s30_arm, fpu_s31_arm, fpu_fpscr_arm, fpu_d0_arm, fpu_d1_arm, 67b9c1b51eSKate Stone fpu_d2_arm, fpu_d3_arm, fpu_d4_arm, fpu_d5_arm, fpu_d6_arm, 68b9c1b51eSKate Stone fpu_d7_arm, fpu_d8_arm, fpu_d9_arm, fpu_d10_arm, fpu_d11_arm, 69b9c1b51eSKate Stone fpu_d12_arm, fpu_d13_arm, fpu_d14_arm, fpu_d15_arm, fpu_d16_arm, 70b9c1b51eSKate Stone fpu_d17_arm, fpu_d18_arm, fpu_d19_arm, fpu_d20_arm, fpu_d21_arm, 71b9c1b51eSKate Stone fpu_d22_arm, fpu_d23_arm, fpu_d24_arm, fpu_d25_arm, fpu_d26_arm, 72b9c1b51eSKate Stone fpu_d27_arm, fpu_d28_arm, fpu_d29_arm, fpu_d30_arm, fpu_d31_arm, 73b9c1b51eSKate Stone fpu_q0_arm, fpu_q1_arm, fpu_q2_arm, fpu_q3_arm, fpu_q4_arm, 74b9c1b51eSKate Stone fpu_q5_arm, fpu_q6_arm, fpu_q7_arm, fpu_q8_arm, fpu_q9_arm, 75b9c1b51eSKate Stone fpu_q10_arm, fpu_q11_arm, fpu_q12_arm, fpu_q13_arm, fpu_q14_arm, 76b4e95a50STamas Berghammer fpu_q15_arm, 773f57216cSOmair Javaid LLDB_INVALID_REGNUM // register sets need to end with this flag 783f57216cSOmair Javaid }; 79b9c1b51eSKate Stone static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == 80b9c1b51eSKate Stone k_num_fpr_registers_arm, 813f57216cSOmair Javaid "g_fpu_regnums_arm has wrong number of register infos"); 823f57216cSOmair Javaid 833f57216cSOmair Javaid namespace { 843f57216cSOmair Javaid // Number of register sets provided by this context. 85b9c1b51eSKate Stone enum { k_num_register_sets = 2 }; 863f57216cSOmair Javaid } 873f57216cSOmair Javaid 883f57216cSOmair Javaid // Register sets for arm. 89b9c1b51eSKate Stone static const RegisterSet g_reg_sets_arm[k_num_register_sets] = { 90b9c1b51eSKate Stone {"General Purpose Registers", "gpr", k_num_gpr_registers_arm, 91b9c1b51eSKate Stone g_gpr_regnums_arm}, 92b9c1b51eSKate Stone {"Floating Point Registers", "fpu", k_num_fpr_registers_arm, 93b9c1b51eSKate Stone g_fpu_regnums_arm}}; 943f57216cSOmair Javaid 95e85e6021STamas Berghammer #if defined(__arm__) 96e85e6021STamas Berghammer 97d37349f3SPavel Labath std::unique_ptr<NativeRegisterContextLinux> 98b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 99d37349f3SPavel Labath const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { 100d37349f3SPavel Labath return llvm::make_unique<NativeRegisterContextLinux_arm>(target_arch, 101d37349f3SPavel Labath native_thread); 102068f8a7eSTamas Berghammer } 103068f8a7eSTamas Berghammer 104e85e6021STamas Berghammer #endif // defined(__arm__) 105e85e6021STamas Berghammer 106b9c1b51eSKate Stone NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm( 107d37349f3SPavel Labath const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 108d37349f3SPavel Labath : NativeRegisterContextLinux(native_thread, 1094b2b6bfbSPavel Labath new RegisterInfoPOSIX_arm(target_arch)) { 110b9c1b51eSKate Stone switch (target_arch.GetMachine()) { 1113f57216cSOmair Javaid case llvm::Triple::arm: 1123f57216cSOmair Javaid m_reg_info.num_registers = k_num_registers_arm; 1133f57216cSOmair Javaid m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; 1143f57216cSOmair Javaid m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; 1153f57216cSOmair Javaid m_reg_info.last_gpr = k_last_gpr_arm; 1163f57216cSOmair Javaid m_reg_info.first_fpr = k_first_fpr_arm; 1173f57216cSOmair Javaid m_reg_info.last_fpr = k_last_fpr_arm; 1183f57216cSOmair Javaid m_reg_info.first_fpr_v = fpu_s0_arm; 1193f57216cSOmair Javaid m_reg_info.last_fpr_v = fpu_s31_arm; 1203f57216cSOmair Javaid m_reg_info.gpr_flags = gpr_cpsr_arm; 1213f57216cSOmair Javaid break; 1223f57216cSOmair Javaid default: 1233f57216cSOmair Javaid assert(false && "Unhandled target architecture."); 1243f57216cSOmair Javaid break; 1253f57216cSOmair Javaid } 1263f57216cSOmair Javaid 1273f57216cSOmair Javaid ::memset(&m_fpr, 0, sizeof(m_fpr)); 1283f57216cSOmair Javaid ::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm)); 1292441aecdSOmair Javaid ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); 130d5ffbad2SOmair Javaid ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs)); 1312441aecdSOmair Javaid 1322441aecdSOmair Javaid // 16 is just a maximum value, query hardware for actual watchpoint count 1332441aecdSOmair Javaid m_max_hwp_supported = 16; 1342441aecdSOmair Javaid m_max_hbp_supported = 16; 1352441aecdSOmair Javaid m_refresh_hwdebug_info = true; 1363f57216cSOmair Javaid } 1373f57216cSOmair Javaid 138b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount() const { 1393f57216cSOmair Javaid return k_num_register_sets; 1403f57216cSOmair Javaid } 1413f57216cSOmair Javaid 142b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount() const { 1431f149204STamas Berghammer uint32_t count = 0; 1441f149204STamas Berghammer for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) 1451f149204STamas Berghammer count += g_reg_sets_arm[set_index].num_registers; 1461f149204STamas Berghammer return count; 1471f149204STamas Berghammer } 1481f149204STamas Berghammer 1493f57216cSOmair Javaid const RegisterSet * 150b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index) const { 1513f57216cSOmair Javaid if (set_index < k_num_register_sets) 1523f57216cSOmair Javaid return &g_reg_sets_arm[set_index]; 1533f57216cSOmair Javaid 1543f57216cSOmair Javaid return nullptr; 1553f57216cSOmair Javaid } 1563f57216cSOmair Javaid 15797206d57SZachary Turner Status 15897206d57SZachary Turner NativeRegisterContextLinux_arm::ReadRegister(const RegisterInfo *reg_info, 159b9c1b51eSKate Stone RegisterValue ®_value) { 16097206d57SZachary Turner Status error; 1613f57216cSOmair Javaid 162b9c1b51eSKate Stone if (!reg_info) { 1633f57216cSOmair Javaid error.SetErrorString("reg_info NULL"); 1643f57216cSOmair Javaid return error; 1653f57216cSOmair Javaid } 1663f57216cSOmair Javaid 1673f57216cSOmair Javaid const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 1683f57216cSOmair Javaid 169b9c1b51eSKate Stone if (IsFPR(reg)) { 170068f8a7eSTamas Berghammer error = ReadFPR(); 171068f8a7eSTamas Berghammer if (error.Fail()) 1723f57216cSOmair Javaid return error; 173b9c1b51eSKate Stone } else { 1743f57216cSOmair Javaid uint32_t full_reg = reg; 175b9c1b51eSKate Stone bool is_subreg = reg_info->invalidate_regs && 176b9c1b51eSKate Stone (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 1773f57216cSOmair Javaid 178b9c1b51eSKate Stone if (is_subreg) { 1793f57216cSOmair Javaid // Read the full aligned 64-bit register. 1803f57216cSOmair Javaid full_reg = reg_info->invalidate_regs[0]; 1813f57216cSOmair Javaid } 1823f57216cSOmair Javaid 1833f57216cSOmair Javaid error = ReadRegisterRaw(full_reg, reg_value); 1843f57216cSOmair Javaid 185b9c1b51eSKate Stone if (error.Success()) { 18605097246SAdrian Prantl // If our read was not aligned (for ah,bh,ch,dh), shift our returned 18705097246SAdrian Prantl // value one byte to the right. 1883f57216cSOmair Javaid if (is_subreg && (reg_info->byte_offset & 0x1)) 1893f57216cSOmair Javaid reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); 1903f57216cSOmair Javaid 191b9c1b51eSKate Stone // If our return byte size was greater than the return value reg size, 19205097246SAdrian Prantl // then use the type specified by reg_info rather than the uint64_t 19305097246SAdrian Prantl // default 1943f57216cSOmair Javaid if (reg_value.GetByteSize() > reg_info->byte_size) 1953f57216cSOmair Javaid reg_value.SetType(reg_info); 1963f57216cSOmair Javaid } 1973f57216cSOmair Javaid return error; 1983f57216cSOmair Javaid } 1993f57216cSOmair Javaid 2003f57216cSOmair Javaid // Get pointer to m_fpr variable and set the data from it. 201c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 202c40e7b17STamas Berghammer assert(fpr_offset < sizeof m_fpr); 203c40e7b17STamas Berghammer uint8_t *src = (uint8_t *)&m_fpr + fpr_offset; 204b9c1b51eSKate Stone switch (reg_info->byte_size) { 2053f57216cSOmair Javaid case 2: 2063f57216cSOmair Javaid reg_value.SetUInt16(*(uint16_t *)src); 2073f57216cSOmair Javaid break; 2083f57216cSOmair Javaid case 4: 2093f57216cSOmair Javaid reg_value.SetUInt32(*(uint32_t *)src); 2103f57216cSOmair Javaid break; 2113f57216cSOmair Javaid case 8: 2123f57216cSOmair Javaid reg_value.SetUInt64(*(uint64_t *)src); 2133f57216cSOmair Javaid break; 214b4e95a50STamas Berghammer case 16: 215b4e95a50STamas Berghammer reg_value.SetBytes(src, 16, GetByteOrder()); 216b4e95a50STamas Berghammer break; 2173f57216cSOmair Javaid default: 2183f57216cSOmair Javaid assert(false && "Unhandled data size."); 219b9c1b51eSKate Stone error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, 220b9c1b51eSKate Stone reg_info->byte_size); 2213f57216cSOmair Javaid break; 2223f57216cSOmair Javaid } 2233f57216cSOmair Javaid 2243f57216cSOmair Javaid return error; 2253f57216cSOmair Javaid } 2263f57216cSOmair Javaid 22797206d57SZachary Turner Status 22897206d57SZachary Turner NativeRegisterContextLinux_arm::WriteRegister(const RegisterInfo *reg_info, 22997206d57SZachary Turner const RegisterValue ®_value) { 2303f57216cSOmair Javaid if (!reg_info) 23197206d57SZachary Turner return Status("reg_info NULL"); 2323f57216cSOmair Javaid 2333f57216cSOmair Javaid const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 2343f57216cSOmair Javaid if (reg_index == LLDB_INVALID_REGNUM) 23597206d57SZachary Turner return Status("no lldb regnum for %s", reg_info && reg_info->name 236b9c1b51eSKate Stone ? reg_info->name 237b9c1b51eSKate Stone : "<unknown register>"); 2383f57216cSOmair Javaid 2393f57216cSOmair Javaid if (IsGPR(reg_index)) 2403f57216cSOmair Javaid return WriteRegisterRaw(reg_index, reg_value); 2413f57216cSOmair Javaid 242b9c1b51eSKate Stone if (IsFPR(reg_index)) { 2433f57216cSOmair Javaid // Get pointer to m_fpr variable and set the data to it. 244c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 245c40e7b17STamas Berghammer assert(fpr_offset < sizeof m_fpr); 246c40e7b17STamas Berghammer uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset; 247b9c1b51eSKate Stone switch (reg_info->byte_size) { 2483f57216cSOmair Javaid case 2: 2493f57216cSOmair Javaid *(uint16_t *)dst = reg_value.GetAsUInt16(); 2503f57216cSOmair Javaid break; 2513f57216cSOmair Javaid case 4: 2523f57216cSOmair Javaid *(uint32_t *)dst = reg_value.GetAsUInt32(); 2533f57216cSOmair Javaid break; 2543f57216cSOmair Javaid case 8: 2553f57216cSOmair Javaid *(uint64_t *)dst = reg_value.GetAsUInt64(); 2563f57216cSOmair Javaid break; 2573f57216cSOmair Javaid default: 2583f57216cSOmair Javaid assert(false && "Unhandled data size."); 25997206d57SZachary Turner return Status("unhandled register data size %" PRIu32, 260b9c1b51eSKate Stone reg_info->byte_size); 2613f57216cSOmair Javaid } 2623f57216cSOmair Javaid 26397206d57SZachary Turner Status error = WriteFPR(); 264068f8a7eSTamas Berghammer if (error.Fail()) 265068f8a7eSTamas Berghammer return error; 2663f57216cSOmair Javaid 26797206d57SZachary Turner return Status(); 2683f57216cSOmair Javaid } 2693f57216cSOmair Javaid 27097206d57SZachary Turner return Status("failed - register wasn't recognized to be a GPR or an FPR, " 271b9c1b51eSKate Stone "write strategy unknown"); 2723f57216cSOmair Javaid } 2733f57216cSOmair Javaid 27497206d57SZachary Turner Status NativeRegisterContextLinux_arm::ReadAllRegisterValues( 275b9c1b51eSKate Stone lldb::DataBufferSP &data_sp) { 27697206d57SZachary Turner Status error; 2773f57216cSOmair Javaid 2783f57216cSOmair Javaid data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 279068f8a7eSTamas Berghammer error = ReadGPR(); 280068f8a7eSTamas Berghammer if (error.Fail()) 2813f57216cSOmair Javaid return error; 2823f57216cSOmair Javaid 283068f8a7eSTamas Berghammer error = ReadFPR(); 284068f8a7eSTamas Berghammer if (error.Fail()) 2853f57216cSOmair Javaid return error; 2863f57216cSOmair Javaid 2873f57216cSOmair Javaid uint8_t *dst = data_sp->GetBytes(); 2883f57216cSOmair Javaid ::memcpy(dst, &m_gpr_arm, GetGPRSize()); 2893f57216cSOmair Javaid dst += GetGPRSize(); 2903f57216cSOmair Javaid ::memcpy(dst, &m_fpr, sizeof(m_fpr)); 2913f57216cSOmair Javaid 2923f57216cSOmair Javaid return error; 2933f57216cSOmair Javaid } 2943f57216cSOmair Javaid 29597206d57SZachary Turner Status NativeRegisterContextLinux_arm::WriteAllRegisterValues( 296b9c1b51eSKate Stone const lldb::DataBufferSP &data_sp) { 29797206d57SZachary Turner Status error; 2983f57216cSOmair Javaid 299b9c1b51eSKate Stone if (!data_sp) { 300b9c1b51eSKate Stone error.SetErrorStringWithFormat( 301b9c1b51eSKate Stone "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", 302b9c1b51eSKate Stone __FUNCTION__); 3033f57216cSOmair Javaid return error; 3043f57216cSOmair Javaid } 3053f57216cSOmair Javaid 306b9c1b51eSKate Stone if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 307b9c1b51eSKate Stone error.SetErrorStringWithFormat( 308b9c1b51eSKate Stone "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " 309b9c1b51eSKate Stone "data size, expected %" PRIu64 ", actual %" PRIu64, 310b9c1b51eSKate Stone __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize()); 3113f57216cSOmair Javaid return error; 3123f57216cSOmair Javaid } 3133f57216cSOmair Javaid 3143f57216cSOmair Javaid uint8_t *src = data_sp->GetBytes(); 315b9c1b51eSKate Stone if (src == nullptr) { 316b9c1b51eSKate Stone error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " 317b9c1b51eSKate Stone "DataBuffer::GetBytes() returned a null " 318b9c1b51eSKate Stone "pointer", 319b9c1b51eSKate Stone __FUNCTION__); 3203f57216cSOmair Javaid return error; 3213f57216cSOmair Javaid } 3223f57216cSOmair Javaid ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize()); 3233f57216cSOmair Javaid 324068f8a7eSTamas Berghammer error = WriteGPR(); 325068f8a7eSTamas Berghammer if (error.Fail()) 3263f57216cSOmair Javaid return error; 3273f57216cSOmair Javaid 3283f57216cSOmair Javaid src += GetRegisterInfoInterface().GetGPRSize(); 3293f57216cSOmair Javaid ::memcpy(&m_fpr, src, sizeof(m_fpr)); 3303f57216cSOmair Javaid 331068f8a7eSTamas Berghammer error = WriteFPR(); 3323f57216cSOmair Javaid if (error.Fail()) 3333f57216cSOmair Javaid return error; 3343f57216cSOmair Javaid 3353f57216cSOmair Javaid return error; 3363f57216cSOmair Javaid } 3373f57216cSOmair Javaid 338b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const { 3393f57216cSOmair Javaid return reg <= m_reg_info.last_gpr; // GPR's come first. 3403f57216cSOmair Javaid } 3413f57216cSOmair Javaid 342b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const { 3433f57216cSOmair Javaid return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 3443f57216cSOmair Javaid } 3453f57216cSOmair Javaid 346d5ffbad2SOmair Javaid uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() { 347d5ffbad2SOmair Javaid Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 348d5ffbad2SOmair Javaid 349*63e5fb76SJonas Devlieghere LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 350d5ffbad2SOmair Javaid 35197206d57SZachary Turner Status error; 352d5ffbad2SOmair Javaid 353d5ffbad2SOmair Javaid // Read hardware breakpoint and watchpoint information. 354d5ffbad2SOmair Javaid error = ReadHardwareDebugInfo(); 355d5ffbad2SOmair Javaid 356d5ffbad2SOmair Javaid if (error.Fail()) 357d5ffbad2SOmair Javaid return 0; 358d5ffbad2SOmair Javaid 359d5ffbad2SOmair Javaid LLDB_LOG(log, "{0}", m_max_hbp_supported); 360d5ffbad2SOmair Javaid return m_max_hbp_supported; 361d5ffbad2SOmair Javaid } 362d5ffbad2SOmair Javaid 3632441aecdSOmair Javaid uint32_t 364b9c1b51eSKate Stone NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr, 365b9c1b51eSKate Stone size_t size) { 366d5ffbad2SOmair Javaid Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 367ea1b6b17SPavel Labath LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size); 3682441aecdSOmair Javaid 3692441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 37097206d57SZachary Turner Status error = ReadHardwareDebugInfo(); 3712441aecdSOmair Javaid 3722441aecdSOmair Javaid if (error.Fail()) 3732441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 3742441aecdSOmair Javaid 3752441aecdSOmair Javaid uint32_t control_value = 0, bp_index = 0; 3762441aecdSOmair Javaid 377d5ffbad2SOmair Javaid // Setup address and control values. 378d5ffbad2SOmair Javaid // Use size to get a hint of arm vs thumb modes. 379d5ffbad2SOmair Javaid switch (size) { 380d5ffbad2SOmair Javaid case 2: 381d5ffbad2SOmair Javaid control_value = (0x3 << 5) | 7; 382d5ffbad2SOmair Javaid addr &= ~1; 383d5ffbad2SOmair Javaid break; 384d5ffbad2SOmair Javaid case 4: 385d5ffbad2SOmair Javaid control_value = (0xfu << 5) | 7; 386d5ffbad2SOmair Javaid addr &= ~3; 387d5ffbad2SOmair Javaid break; 388d5ffbad2SOmair Javaid default: 3892441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 390d5ffbad2SOmair Javaid } 3912441aecdSOmair Javaid 392d5ffbad2SOmair Javaid // Iterate over stored breakpoints and find a free bp_index 3932441aecdSOmair Javaid bp_index = LLDB_INVALID_INDEX32; 394b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 395b9c1b51eSKate Stone if ((m_hbr_regs[i].control & 1) == 0) { 3962441aecdSOmair Javaid bp_index = i; // Mark last free slot 397d5ffbad2SOmair Javaid } else if (m_hbr_regs[i].address == addr) { 398d5ffbad2SOmair Javaid return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints. 3992441aecdSOmair Javaid } 4002441aecdSOmair Javaid } 4012441aecdSOmair Javaid 4022441aecdSOmair Javaid if (bp_index == LLDB_INVALID_INDEX32) 4032441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 4042441aecdSOmair Javaid 405d5ffbad2SOmair Javaid // Update breakpoint in local cache 406d5ffbad2SOmair Javaid m_hbr_regs[bp_index].real_addr = addr; 4072441aecdSOmair Javaid m_hbr_regs[bp_index].address = addr; 4082441aecdSOmair Javaid m_hbr_regs[bp_index].control = control_value; 4092441aecdSOmair Javaid 4102441aecdSOmair Javaid // PTRACE call to set corresponding hardware breakpoint register. 4112441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index); 4122441aecdSOmair Javaid 413b9c1b51eSKate Stone if (error.Fail()) { 414d5510d1eSOmair Javaid m_hbr_regs[bp_index].address = 0; 415d5510d1eSOmair Javaid m_hbr_regs[bp_index].control &= ~1; 416d5510d1eSOmair Javaid 4172441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 4182441aecdSOmair Javaid } 4192441aecdSOmair Javaid 4202441aecdSOmair Javaid return bp_index; 4212441aecdSOmair Javaid } 4222441aecdSOmair Javaid 423b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) { 424d5ffbad2SOmair Javaid Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 425ea1b6b17SPavel Labath LLDB_LOG(log, "hw_idx: {0}", hw_idx); 4262441aecdSOmair Javaid 4272441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 42897206d57SZachary Turner Status error = ReadHardwareDebugInfo(); 4292441aecdSOmair Javaid 4302441aecdSOmair Javaid if (error.Fail()) 4314aa984c1SOmair Javaid return false; 4322441aecdSOmair Javaid 4332441aecdSOmair Javaid if (hw_idx >= m_max_hbp_supported) 4342441aecdSOmair Javaid return false; 4352441aecdSOmair Javaid 436d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 437d5510d1eSOmair Javaid lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; 438d5510d1eSOmair Javaid uint32_t tempControl = m_hbr_regs[hw_idx].control; 439d5510d1eSOmair Javaid 4402441aecdSOmair Javaid m_hbr_regs[hw_idx].control &= ~1; 4412441aecdSOmair Javaid m_hbr_regs[hw_idx].address = 0; 4422441aecdSOmair Javaid 4432441aecdSOmair Javaid // PTRACE call to clear corresponding hardware breakpoint register. 444d5ffbad2SOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx); 4452441aecdSOmair Javaid 446b9c1b51eSKate Stone if (error.Fail()) { 447d5510d1eSOmair Javaid m_hbr_regs[hw_idx].control = tempControl; 448d5510d1eSOmair Javaid m_hbr_regs[hw_idx].address = tempAddr; 449d5510d1eSOmair Javaid 4504aa984c1SOmair Javaid return false; 451d5510d1eSOmair Javaid } 4522441aecdSOmair Javaid 4532441aecdSOmair Javaid return true; 4542441aecdSOmair Javaid } 4552441aecdSOmair Javaid 45697206d57SZachary Turner Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex( 457d5ffbad2SOmair Javaid uint32_t &bp_index, lldb::addr_t trap_addr) { 458d5ffbad2SOmair Javaid Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 459d5ffbad2SOmair Javaid 460*63e5fb76SJonas Devlieghere LLDB_LOGF(log, "NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 461d5ffbad2SOmair Javaid 462d5ffbad2SOmair Javaid lldb::addr_t break_addr; 463d5ffbad2SOmair Javaid 464d5ffbad2SOmair Javaid for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) { 465d5ffbad2SOmair Javaid break_addr = m_hbr_regs[bp_index].address; 466d5ffbad2SOmair Javaid 467d5ffbad2SOmair Javaid if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) { 468d5ffbad2SOmair Javaid m_hbr_regs[bp_index].hit_addr = trap_addr; 46997206d57SZachary Turner return Status(); 470d5ffbad2SOmair Javaid } 471d5ffbad2SOmair Javaid } 472d5ffbad2SOmair Javaid 473d5ffbad2SOmair Javaid bp_index = LLDB_INVALID_INDEX32; 47497206d57SZachary Turner return Status(); 475d5ffbad2SOmair Javaid } 476d5ffbad2SOmair Javaid 47797206d57SZachary Turner Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() { 478d5ffbad2SOmair Javaid Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 479d5ffbad2SOmair Javaid 480*63e5fb76SJonas Devlieghere LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 481d5ffbad2SOmair Javaid 48297206d57SZachary Turner Status error; 483d5ffbad2SOmair Javaid 484d5ffbad2SOmair Javaid // Read hardware breakpoint and watchpoint information. 485d5ffbad2SOmair Javaid error = ReadHardwareDebugInfo(); 486d5ffbad2SOmair Javaid 487d5ffbad2SOmair Javaid if (error.Fail()) 488d5ffbad2SOmair Javaid return error; 489d5ffbad2SOmair Javaid 490d5ffbad2SOmair Javaid lldb::addr_t tempAddr = 0; 491d5ffbad2SOmair Javaid uint32_t tempControl = 0; 492d5ffbad2SOmair Javaid 493d5ffbad2SOmair Javaid for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 494d5ffbad2SOmair Javaid if (m_hbr_regs[i].control & 0x01) { 495d5ffbad2SOmair Javaid // Create a backup we can revert to in case of failure. 496d5ffbad2SOmair Javaid tempAddr = m_hbr_regs[i].address; 497d5ffbad2SOmair Javaid tempControl = m_hbr_regs[i].control; 498d5ffbad2SOmair Javaid 499d5ffbad2SOmair Javaid // Clear breakpoints in local cache 500d5ffbad2SOmair Javaid m_hbr_regs[i].control &= ~1; 501d5ffbad2SOmair Javaid m_hbr_regs[i].address = 0; 502d5ffbad2SOmair Javaid 503d5ffbad2SOmair Javaid // Ptrace call to update hardware debug registers 504d5ffbad2SOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK, i); 505d5ffbad2SOmair Javaid 506d5ffbad2SOmair Javaid if (error.Fail()) { 507d5ffbad2SOmair Javaid m_hbr_regs[i].control = tempControl; 508d5ffbad2SOmair Javaid m_hbr_regs[i].address = tempAddr; 509d5ffbad2SOmair Javaid 510d5ffbad2SOmair Javaid return error; 511d5ffbad2SOmair Javaid } 512d5ffbad2SOmair Javaid } 513d5ffbad2SOmair Javaid } 514d5ffbad2SOmair Javaid 51597206d57SZachary Turner return Status(); 5162441aecdSOmair Javaid } 5172441aecdSOmair Javaid 518b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() { 519ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 5202441aecdSOmair Javaid 5212441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 52297206d57SZachary Turner Status error = ReadHardwareDebugInfo(); 5232441aecdSOmair Javaid 5242441aecdSOmair Javaid if (error.Fail()) 52562661473SOmair Javaid return 0; 5262441aecdSOmair Javaid 527ea1b6b17SPavel Labath LLDB_LOG(log, "{0}", m_max_hwp_supported); 5282441aecdSOmair Javaid return m_max_hwp_supported; 5292441aecdSOmair Javaid } 5302441aecdSOmair Javaid 531b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint( 532b9c1b51eSKate Stone lldb::addr_t addr, size_t size, uint32_t watch_flags) { 533ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 534ea1b6b17SPavel Labath LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, 535ea1b6b17SPavel Labath watch_flags); 5362441aecdSOmair Javaid 5372441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 53897206d57SZachary Turner Status error = ReadHardwareDebugInfo(); 5392441aecdSOmair Javaid 5402441aecdSOmair Javaid if (error.Fail()) 5412441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5422441aecdSOmair Javaid 5432441aecdSOmair Javaid uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0; 544c6dc90efSOmair Javaid lldb::addr_t real_addr = addr; 5452441aecdSOmair Javaid 54605097246SAdrian Prantl // Check if we are setting watchpoint other than read/write/access Also 54705097246SAdrian Prantl // update watchpoint flag to match Arm write-read bit configuration. 548b9c1b51eSKate Stone switch (watch_flags) { 5492441aecdSOmair Javaid case 1: 5502441aecdSOmair Javaid watch_flags = 2; 5512441aecdSOmair Javaid break; 5522441aecdSOmair Javaid case 2: 5532441aecdSOmair Javaid watch_flags = 1; 5542441aecdSOmair Javaid break; 5552441aecdSOmair Javaid case 3: 5562441aecdSOmair Javaid break; 5572441aecdSOmair Javaid default: 5582441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5592441aecdSOmair Javaid } 5602441aecdSOmair Javaid 5612441aecdSOmair Javaid // Can't watch zero bytes 5622441aecdSOmair Javaid // Can't watch more than 4 bytes per WVR/WCR pair 5632441aecdSOmair Javaid 5642441aecdSOmair Javaid if (size == 0 || size > 4) 5652441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5662441aecdSOmair Javaid 56705097246SAdrian Prantl // Check 4-byte alignment for hardware watchpoint target address. Below is a 56805097246SAdrian Prantl // hack to recalculate address and size in order to make sure we can watch 56905097246SAdrian Prantl // non 4-byte alligned addresses as well. 570b9c1b51eSKate Stone if (addr & 0x03) { 571c6dc90efSOmair Javaid uint8_t watch_mask = (addr & 0x03) + size; 572c6dc90efSOmair Javaid 573c6dc90efSOmair Javaid if (watch_mask > 0x04) 574c6dc90efSOmair Javaid return LLDB_INVALID_INDEX32; 575c6dc90efSOmair Javaid else if (watch_mask <= 0x02) 576c6dc90efSOmair Javaid size = 2; 577c6dc90efSOmair Javaid else if (watch_mask <= 0x04) 578c6dc90efSOmair Javaid size = 4; 579c6dc90efSOmair Javaid 580c6dc90efSOmair Javaid addr = addr & (~0x03); 581c6dc90efSOmair Javaid } 582c6dc90efSOmair Javaid 5832441aecdSOmair Javaid // We can only watch up to four bytes that follow a 4 byte aligned address 5842441aecdSOmair Javaid // per watchpoint register pair, so make sure we can properly encode this. 5852441aecdSOmair Javaid addr_word_offset = addr % 4; 5862441aecdSOmair Javaid byte_mask = ((1u << size) - 1u) << addr_word_offset; 5872441aecdSOmair Javaid 5882441aecdSOmair Javaid // Check if we need multiple watchpoint register 5892441aecdSOmair Javaid if (byte_mask > 0xfu) 5902441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5912441aecdSOmair Javaid 5922441aecdSOmair Javaid // Setup control value 5932441aecdSOmair Javaid // Make the byte_mask into a valid Byte Address Select mask 5942441aecdSOmair Javaid control_value = byte_mask << 5; 5952441aecdSOmair Javaid 5962441aecdSOmair Javaid // Turn on appropriate watchpoint flags read or write 5972441aecdSOmair Javaid control_value |= (watch_flags << 3); 5982441aecdSOmair Javaid 5992441aecdSOmair Javaid // Enable this watchpoint and make it stop in privileged or user mode; 6002441aecdSOmair Javaid control_value |= 7; 6012441aecdSOmair Javaid 6022441aecdSOmair Javaid // Make sure bits 1:0 are clear in our address 6032441aecdSOmair Javaid addr &= ~((lldb::addr_t)3); 6042441aecdSOmair Javaid 60505ac4c44SOmair Javaid // Iterate over stored watchpoints and find a free wp_index 6062441aecdSOmair Javaid wp_index = LLDB_INVALID_INDEX32; 607b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 608b9c1b51eSKate Stone if ((m_hwp_regs[i].control & 1) == 0) { 6092441aecdSOmair Javaid wp_index = i; // Mark last free slot 61005ac4c44SOmair Javaid } else if (m_hwp_regs[i].address == addr) { 61105ac4c44SOmair Javaid return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. 6122441aecdSOmair Javaid } 6132441aecdSOmair Javaid } 6142441aecdSOmair Javaid 6152441aecdSOmair Javaid if (wp_index == LLDB_INVALID_INDEX32) 6162441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 6172441aecdSOmair Javaid 6182441aecdSOmair Javaid // Update watchpoint in local cache 619c6dc90efSOmair Javaid m_hwp_regs[wp_index].real_addr = real_addr; 6202441aecdSOmair Javaid m_hwp_regs[wp_index].address = addr; 6212441aecdSOmair Javaid m_hwp_regs[wp_index].control = control_value; 6222441aecdSOmair Javaid 6232441aecdSOmair Javaid // PTRACE call to set corresponding watchpoint register. 6242441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); 6252441aecdSOmair Javaid 626b9c1b51eSKate Stone if (error.Fail()) { 627d5510d1eSOmair Javaid m_hwp_regs[wp_index].address = 0; 628d5510d1eSOmair Javaid m_hwp_regs[wp_index].control &= ~1; 629d5510d1eSOmair Javaid 6302441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 6312441aecdSOmair Javaid } 6322441aecdSOmair Javaid 6332441aecdSOmair Javaid return wp_index; 6342441aecdSOmair Javaid } 6352441aecdSOmair Javaid 636b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint( 637b9c1b51eSKate Stone uint32_t wp_index) { 638ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 639ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}", wp_index); 6402441aecdSOmair Javaid 6412441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 64297206d57SZachary Turner Status error = ReadHardwareDebugInfo(); 6432441aecdSOmair Javaid 6442441aecdSOmair Javaid if (error.Fail()) 6454aa984c1SOmair Javaid return false; 6462441aecdSOmair Javaid 6472441aecdSOmair Javaid if (wp_index >= m_max_hwp_supported) 6482441aecdSOmair Javaid return false; 6492441aecdSOmair Javaid 650d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 651d5510d1eSOmair Javaid lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 652d5510d1eSOmair Javaid uint32_t tempControl = m_hwp_regs[wp_index].control; 653d5510d1eSOmair Javaid 6542441aecdSOmair Javaid // Update watchpoint in local cache 6552441aecdSOmair Javaid m_hwp_regs[wp_index].control &= ~1; 6562441aecdSOmair Javaid m_hwp_regs[wp_index].address = 0; 6572441aecdSOmair Javaid 6582441aecdSOmair Javaid // Ptrace call to update hardware debug registers 6592441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); 6602441aecdSOmair Javaid 661b9c1b51eSKate Stone if (error.Fail()) { 662d5510d1eSOmair Javaid m_hwp_regs[wp_index].control = tempControl; 663d5510d1eSOmair Javaid m_hwp_regs[wp_index].address = tempAddr; 664d5510d1eSOmair Javaid 6652441aecdSOmair Javaid return false; 666d5510d1eSOmair Javaid } 6672441aecdSOmair Javaid 6682441aecdSOmair Javaid return true; 6692441aecdSOmair Javaid } 6702441aecdSOmair Javaid 67197206d57SZachary Turner Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() { 6722441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 67397206d57SZachary Turner Status error = ReadHardwareDebugInfo(); 6742441aecdSOmair Javaid 6752441aecdSOmair Javaid if (error.Fail()) 6762441aecdSOmair Javaid return error; 6772441aecdSOmair Javaid 678d5510d1eSOmair Javaid lldb::addr_t tempAddr = 0; 67905ac4c44SOmair Javaid uint32_t tempControl = 0; 680d5510d1eSOmair Javaid 681b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 682b9c1b51eSKate Stone if (m_hwp_regs[i].control & 0x01) { 683d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 684d5510d1eSOmair Javaid tempAddr = m_hwp_regs[i].address; 685d5510d1eSOmair Javaid tempControl = m_hwp_regs[i].control; 686d5510d1eSOmair Javaid 6872441aecdSOmair Javaid // Clear watchpoints in local cache 6882441aecdSOmair Javaid m_hwp_regs[i].control &= ~1; 6892441aecdSOmair Javaid m_hwp_regs[i].address = 0; 6902441aecdSOmair Javaid 6912441aecdSOmair Javaid // Ptrace call to update hardware debug registers 6922441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, i); 6932441aecdSOmair Javaid 694b9c1b51eSKate Stone if (error.Fail()) { 695d5510d1eSOmair Javaid m_hwp_regs[i].control = tempControl; 696d5510d1eSOmair Javaid m_hwp_regs[i].address = tempAddr; 697d5510d1eSOmair Javaid 6982441aecdSOmair Javaid return error; 6992441aecdSOmair Javaid } 7002441aecdSOmair Javaid } 701d5510d1eSOmair Javaid } 7022441aecdSOmair Javaid 70397206d57SZachary Turner return Status(); 7042441aecdSOmair Javaid } 7052441aecdSOmair Javaid 706b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) { 707ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 708ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}", wp_index); 7092441aecdSOmair Javaid 710b9c1b51eSKate Stone switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) { 7112441aecdSOmair Javaid case 0x01: 7122441aecdSOmair Javaid return 1; 7132441aecdSOmair Javaid case 0x03: 7142441aecdSOmair Javaid return 2; 7152441aecdSOmair Javaid case 0x07: 7162441aecdSOmair Javaid return 3; 7172441aecdSOmair Javaid case 0x0f: 7182441aecdSOmair Javaid return 4; 7192441aecdSOmair Javaid default: 7202441aecdSOmair Javaid return 0; 7212441aecdSOmair Javaid } 7222441aecdSOmair Javaid } 723b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) { 724ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 725ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}", wp_index); 7262441aecdSOmair Javaid 7272441aecdSOmair Javaid if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 7282441aecdSOmair Javaid return true; 7292441aecdSOmair Javaid else 7302441aecdSOmair Javaid return false; 7312441aecdSOmair Javaid } 7322441aecdSOmair Javaid 73397206d57SZachary Turner Status 73497206d57SZachary Turner NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index, 73597206d57SZachary Turner lldb::addr_t trap_addr) { 736ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 737ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); 7382441aecdSOmair Javaid 7392441aecdSOmair Javaid uint32_t watch_size; 7402441aecdSOmair Javaid lldb::addr_t watch_addr; 7412441aecdSOmair Javaid 742b9c1b51eSKate Stone for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { 7432441aecdSOmair Javaid watch_size = GetWatchpointSize(wp_index); 7442441aecdSOmair Javaid watch_addr = m_hwp_regs[wp_index].address; 7452441aecdSOmair Javaid 74605ac4c44SOmair Javaid if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && 74705ac4c44SOmair Javaid trap_addr < watch_addr + watch_size) { 748c6dc90efSOmair Javaid m_hwp_regs[wp_index].hit_addr = trap_addr; 74997206d57SZachary Turner return Status(); 7502441aecdSOmair Javaid } 7512441aecdSOmair Javaid } 7522441aecdSOmair Javaid 7532441aecdSOmair Javaid wp_index = LLDB_INVALID_INDEX32; 75497206d57SZachary Turner return Status(); 7552441aecdSOmair Javaid } 7562441aecdSOmair Javaid 7572441aecdSOmair Javaid lldb::addr_t 758b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) { 759ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 760ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}", wp_index); 7612441aecdSOmair Javaid 7622441aecdSOmair Javaid if (wp_index >= m_max_hwp_supported) 7632441aecdSOmair Javaid return LLDB_INVALID_ADDRESS; 7642441aecdSOmair Javaid 7652441aecdSOmair Javaid if (WatchpointIsEnabled(wp_index)) 766c6dc90efSOmair Javaid return m_hwp_regs[wp_index].real_addr; 767c6dc90efSOmair Javaid else 768c6dc90efSOmair Javaid return LLDB_INVALID_ADDRESS; 769c6dc90efSOmair Javaid } 770c6dc90efSOmair Javaid 771c6dc90efSOmair Javaid lldb::addr_t 772b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) { 773ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 774ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}", wp_index); 775c6dc90efSOmair Javaid 776c6dc90efSOmair Javaid if (wp_index >= m_max_hwp_supported) 777c6dc90efSOmair Javaid return LLDB_INVALID_ADDRESS; 778c6dc90efSOmair Javaid 779c6dc90efSOmair Javaid if (WatchpointIsEnabled(wp_index)) 780c6dc90efSOmair Javaid return m_hwp_regs[wp_index].hit_addr; 7812441aecdSOmair Javaid else 7822441aecdSOmair Javaid return LLDB_INVALID_ADDRESS; 7832441aecdSOmair Javaid } 7842441aecdSOmair Javaid 78597206d57SZachary Turner Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() { 78697206d57SZachary Turner Status error; 7872441aecdSOmair Javaid 788b9c1b51eSKate Stone if (!m_refresh_hwdebug_info) { 78997206d57SZachary Turner return Status(); 7902441aecdSOmair Javaid } 7912441aecdSOmair Javaid 7922441aecdSOmair Javaid unsigned int cap_val; 7932441aecdSOmair Javaid 794b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), 795b9c1b51eSKate Stone nullptr, &cap_val, 796b9c1b51eSKate Stone sizeof(unsigned int)); 7972441aecdSOmair Javaid 7982441aecdSOmair Javaid if (error.Fail()) 7992441aecdSOmair Javaid return error; 8002441aecdSOmair Javaid 8012441aecdSOmair Javaid m_max_hwp_supported = (cap_val >> 8) & 0xff; 8022441aecdSOmair Javaid m_max_hbp_supported = cap_val & 0xff; 8032441aecdSOmair Javaid m_refresh_hwdebug_info = false; 8042441aecdSOmair Javaid 8052441aecdSOmair Javaid return error; 8062441aecdSOmair Javaid } 8072441aecdSOmair Javaid 80897206d57SZachary Turner Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, 809b9c1b51eSKate Stone int hwb_index) { 81097206d57SZachary Turner Status error; 8112441aecdSOmair Javaid 8122441aecdSOmair Javaid lldb::addr_t *addr_buf; 8132441aecdSOmair Javaid uint32_t *ctrl_buf; 8142441aecdSOmair Javaid 815b9c1b51eSKate Stone if (hwbType == eDREGTypeWATCH) { 8162441aecdSOmair Javaid addr_buf = &m_hwp_regs[hwb_index].address; 8172441aecdSOmair Javaid ctrl_buf = &m_hwp_regs[hwb_index].control; 8182441aecdSOmair Javaid 819b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 820b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 821b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf, 822b9c1b51eSKate Stone sizeof(unsigned int)); 8232441aecdSOmair Javaid 8242441aecdSOmair Javaid if (error.Fail()) 8252441aecdSOmair Javaid return error; 8262441aecdSOmair Javaid 827b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 828b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 829b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf, 830b9c1b51eSKate Stone sizeof(unsigned int)); 831b9c1b51eSKate Stone } else { 832d5ffbad2SOmair Javaid addr_buf = &m_hbr_regs[hwb_index].address; 833d5ffbad2SOmair Javaid ctrl_buf = &m_hbr_regs[hwb_index].control; 8342441aecdSOmair Javaid 835b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 836b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 837b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf, 838b9c1b51eSKate Stone sizeof(unsigned int)); 8392441aecdSOmair Javaid 8402441aecdSOmair Javaid if (error.Fail()) 8412441aecdSOmair Javaid return error; 8422441aecdSOmair Javaid 843b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 844b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 845b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf, 846b9c1b51eSKate Stone sizeof(unsigned int)); 8472441aecdSOmair Javaid } 8482441aecdSOmair Javaid 8492441aecdSOmair Javaid return error; 8502441aecdSOmair Javaid } 851c40e7b17STamas Berghammer 852b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset( 853b9c1b51eSKate Stone const RegisterInfo *reg_info) const { 854b9c1b51eSKate Stone return reg_info->byte_offset - 855b9c1b51eSKate Stone GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; 856c40e7b17STamas Berghammer } 857c40e7b17STamas Berghammer 85897206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoReadRegisterValue( 859b9c1b51eSKate Stone uint32_t offset, const char *reg_name, uint32_t size, 860b9c1b51eSKate Stone RegisterValue &value) { 861b9c1b51eSKate Stone // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android 86205097246SAdrian Prantl // devices (always return "Bad address"). To avoid using PTRACE_PEEKUSER we 86305097246SAdrian Prantl // read out the full GPR register set instead. This approach is about 4 times 86405097246SAdrian Prantl // slower but the performance overhead is negligible in comparision to 86505097246SAdrian Prantl // processing time in lldb-server. 866e85e6021STamas Berghammer assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); 867e85e6021STamas Berghammer if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) 86897206d57SZachary Turner return Status("Register isn't fit into the size of the GPR area"); 869e85e6021STamas Berghammer 87097206d57SZachary Turner Status error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm)); 871e85e6021STamas Berghammer if (error.Fail()) 872e85e6021STamas Berghammer return error; 873e85e6021STamas Berghammer 874e85e6021STamas Berghammer value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]); 87597206d57SZachary Turner return Status(); 876e85e6021STamas Berghammer } 877e85e6021STamas Berghammer 87897206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoWriteRegisterValue( 879b9c1b51eSKate Stone uint32_t offset, const char *reg_name, const RegisterValue &value) { 880b9c1b51eSKate Stone // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android 88105097246SAdrian Prantl // devices (always return "Bad address"). To avoid using PTRACE_POKEUSER we 88205097246SAdrian Prantl // read out the full GPR register set, modify the requested register and 88305097246SAdrian Prantl // write it back. This approach is about 4 times slower but the performance 88405097246SAdrian Prantl // overhead is negligible in comparision to processing time in lldb-server. 885ce26b7a6STamas Berghammer assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); 886ce26b7a6STamas Berghammer if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) 88797206d57SZachary Turner return Status("Register isn't fit into the size of the GPR area"); 888ce26b7a6STamas Berghammer 88997206d57SZachary Turner Status error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm)); 890ce26b7a6STamas Berghammer if (error.Fail()) 891ce26b7a6STamas Berghammer return error; 892ce26b7a6STamas Berghammer 893a7d7f7cfSOmair Javaid uint32_t reg_value = value.GetAsUInt32(); 894a7d7f7cfSOmair Javaid // As precaution for an undefined behavior encountered while setting PC we 895a7d7f7cfSOmair Javaid // will clear thumb bit of new PC if we are already in thumb mode; that is 896a7d7f7cfSOmair Javaid // CPSR thumb mode bit is set. 897b9c1b51eSKate Stone if (offset / sizeof(uint32_t) == gpr_pc_arm) { 89805097246SAdrian Prantl // Check if we are already in thumb mode and thumb bit of current PC is 89905097246SAdrian Prantl // read out to be zero and thumb bit of next PC is read out to be one. 900b9c1b51eSKate Stone if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) && 901b9c1b51eSKate Stone (value.GetAsUInt32() & 0x01)) { 902a7d7f7cfSOmair Javaid reg_value &= (~1ull); 903a7d7f7cfSOmair Javaid } 904a7d7f7cfSOmair Javaid } 905a7d7f7cfSOmair Javaid 906a7d7f7cfSOmair Javaid m_gpr_arm[offset / sizeof(uint32_t)] = reg_value; 907ce26b7a6STamas Berghammer return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm)); 908ce26b7a6STamas Berghammer } 909ce26b7a6STamas Berghammer 91097206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoReadGPR(void *buf, size_t buf_size) { 911e85e6021STamas Berghammer #ifdef __arm__ 912e85e6021STamas Berghammer return NativeRegisterContextLinux::DoReadGPR(buf, buf_size); 913e85e6021STamas Berghammer #else // __aarch64__ 914e85e6021STamas Berghammer struct iovec ioVec; 915e85e6021STamas Berghammer ioVec.iov_base = buf; 916e85e6021STamas Berghammer ioVec.iov_len = buf_size; 917e85e6021STamas Berghammer 918e85e6021STamas Berghammer return ReadRegisterSet(&ioVec, buf_size, NT_PRSTATUS); 919e85e6021STamas Berghammer #endif // __arm__ 920e85e6021STamas Berghammer } 921e85e6021STamas Berghammer 92297206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoWriteGPR(void *buf, size_t buf_size) { 923e85e6021STamas Berghammer #ifdef __arm__ 924e85e6021STamas Berghammer return NativeRegisterContextLinux::DoWriteGPR(buf, buf_size); 925e85e6021STamas Berghammer #else // __aarch64__ 926e85e6021STamas Berghammer struct iovec ioVec; 927e85e6021STamas Berghammer ioVec.iov_base = buf; 928e85e6021STamas Berghammer ioVec.iov_len = buf_size; 929e85e6021STamas Berghammer 930e85e6021STamas Berghammer return WriteRegisterSet(&ioVec, buf_size, NT_PRSTATUS); 931e85e6021STamas Berghammer #endif // __arm__ 932e85e6021STamas Berghammer } 933e85e6021STamas Berghammer 93497206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size) { 935e85e6021STamas Berghammer #ifdef __arm__ 936b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(), 937b9c1b51eSKate Stone nullptr, buf, buf_size); 938e85e6021STamas Berghammer #else // __aarch64__ 939e85e6021STamas Berghammer struct iovec ioVec; 940e85e6021STamas Berghammer ioVec.iov_base = buf; 941e85e6021STamas Berghammer ioVec.iov_len = buf_size; 942e85e6021STamas Berghammer 943e85e6021STamas Berghammer return ReadRegisterSet(&ioVec, buf_size, NT_ARM_VFP); 944e85e6021STamas Berghammer #endif // __arm__ 945ce26b7a6STamas Berghammer } 946ce26b7a6STamas Berghammer 94797206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size) { 948e85e6021STamas Berghammer #ifdef __arm__ 949b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(), 950b9c1b51eSKate Stone nullptr, buf, buf_size); 951e85e6021STamas Berghammer #else // __aarch64__ 952e85e6021STamas Berghammer struct iovec ioVec; 953e85e6021STamas Berghammer ioVec.iov_base = buf; 954e85e6021STamas Berghammer ioVec.iov_len = buf_size; 955e85e6021STamas Berghammer 956e85e6021STamas Berghammer return WriteRegisterSet(&ioVec, buf_size, NT_ARM_VFP); 957e85e6021STamas Berghammer #endif // __arm__ 958ce26b7a6STamas Berghammer } 959ce26b7a6STamas Berghammer 960e85e6021STamas Berghammer #endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 961