13f57216cSOmair Javaid //===-- NativeRegisterContextLinux_arm.cpp --------------------*- C++ -*-===// 23f57216cSOmair Javaid // 33f57216cSOmair Javaid // The LLVM Compiler Infrastructure 43f57216cSOmair Javaid // 53f57216cSOmair Javaid // This file is distributed under the University of Illinois Open Source 63f57216cSOmair Javaid // License. See LICENSE.TXT for details. 73f57216cSOmair Javaid // 83f57216cSOmair Javaid //===----------------------------------------------------------------------===// 93f57216cSOmair Javaid 10e85e6021STamas Berghammer #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 11068f8a7eSTamas Berghammer 123f57216cSOmair Javaid #include "NativeRegisterContextLinux_arm.h" 133f57216cSOmair Javaid 143f57216cSOmair Javaid #include "lldb/Core/DataBufferHeap.h" 153f57216cSOmair Javaid #include "lldb/Core/Error.h" 162441aecdSOmair Javaid #include "lldb/Core/Log.h" 173f57216cSOmair Javaid #include "lldb/Core/RegisterValue.h" 18068f8a7eSTamas Berghammer 19e85e6021STamas Berghammer #include "Plugins/Process/Linux/Procfs.h" 20068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_arm.h" 213f57216cSOmair Javaid 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. 47*b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_arm[] = { 48*b9c1b51eSKate Stone gpr_r0_arm, gpr_r1_arm, gpr_r2_arm, gpr_r3_arm, gpr_r4_arm, 49*b9c1b51eSKate Stone gpr_r5_arm, gpr_r6_arm, gpr_r7_arm, gpr_r8_arm, gpr_r9_arm, 50*b9c1b51eSKate Stone gpr_r10_arm, gpr_r11_arm, gpr_r12_arm, gpr_sp_arm, gpr_lr_arm, 51*b9c1b51eSKate Stone gpr_pc_arm, gpr_cpsr_arm, 523f57216cSOmair Javaid LLDB_INVALID_REGNUM // register sets need to end with this flag 533f57216cSOmair Javaid }; 54*b9c1b51eSKate Stone static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == 55*b9c1b51eSKate 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. 59*b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_arm[] = { 60*b9c1b51eSKate Stone fpu_s0_arm, fpu_s1_arm, fpu_s2_arm, fpu_s3_arm, fpu_s4_arm, 61*b9c1b51eSKate Stone fpu_s5_arm, fpu_s6_arm, fpu_s7_arm, fpu_s8_arm, fpu_s9_arm, 62*b9c1b51eSKate Stone fpu_s10_arm, fpu_s11_arm, fpu_s12_arm, fpu_s13_arm, fpu_s14_arm, 63*b9c1b51eSKate Stone fpu_s15_arm, fpu_s16_arm, fpu_s17_arm, fpu_s18_arm, fpu_s19_arm, 64*b9c1b51eSKate Stone fpu_s20_arm, fpu_s21_arm, fpu_s22_arm, fpu_s23_arm, fpu_s24_arm, 65*b9c1b51eSKate Stone fpu_s25_arm, fpu_s26_arm, fpu_s27_arm, fpu_s28_arm, fpu_s29_arm, 66*b9c1b51eSKate Stone fpu_s30_arm, fpu_s31_arm, fpu_fpscr_arm, fpu_d0_arm, fpu_d1_arm, 67*b9c1b51eSKate Stone fpu_d2_arm, fpu_d3_arm, fpu_d4_arm, fpu_d5_arm, fpu_d6_arm, 68*b9c1b51eSKate Stone fpu_d7_arm, fpu_d8_arm, fpu_d9_arm, fpu_d10_arm, fpu_d11_arm, 69*b9c1b51eSKate Stone fpu_d12_arm, fpu_d13_arm, fpu_d14_arm, fpu_d15_arm, fpu_d16_arm, 70*b9c1b51eSKate Stone fpu_d17_arm, fpu_d18_arm, fpu_d19_arm, fpu_d20_arm, fpu_d21_arm, 71*b9c1b51eSKate Stone fpu_d22_arm, fpu_d23_arm, fpu_d24_arm, fpu_d25_arm, fpu_d26_arm, 72*b9c1b51eSKate Stone fpu_d27_arm, fpu_d28_arm, fpu_d29_arm, fpu_d30_arm, fpu_d31_arm, 73*b9c1b51eSKate Stone fpu_q0_arm, fpu_q1_arm, fpu_q2_arm, fpu_q3_arm, fpu_q4_arm, 74*b9c1b51eSKate Stone fpu_q5_arm, fpu_q6_arm, fpu_q7_arm, fpu_q8_arm, fpu_q9_arm, 75*b9c1b51eSKate 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 }; 79*b9c1b51eSKate Stone static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == 80*b9c1b51eSKate 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. 85*b9c1b51eSKate Stone enum { k_num_register_sets = 2 }; 863f57216cSOmair Javaid } 873f57216cSOmair Javaid 883f57216cSOmair Javaid // Register sets for arm. 89*b9c1b51eSKate Stone static const RegisterSet g_reg_sets_arm[k_num_register_sets] = { 90*b9c1b51eSKate Stone {"General Purpose Registers", "gpr", k_num_gpr_registers_arm, 91*b9c1b51eSKate Stone g_gpr_regnums_arm}, 92*b9c1b51eSKate Stone {"Floating Point Registers", "fpu", k_num_fpr_registers_arm, 93*b9c1b51eSKate Stone g_fpu_regnums_arm}}; 943f57216cSOmair Javaid 95e85e6021STamas Berghammer #if defined(__arm__) 96e85e6021STamas Berghammer 97068f8a7eSTamas Berghammer NativeRegisterContextLinux * 98*b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 99*b9c1b51eSKate Stone const ArchSpec &target_arch, NativeThreadProtocol &native_thread, 100*b9c1b51eSKate Stone uint32_t concrete_frame_idx) { 101*b9c1b51eSKate Stone return new NativeRegisterContextLinux_arm(target_arch, native_thread, 102*b9c1b51eSKate Stone concrete_frame_idx); 103068f8a7eSTamas Berghammer } 104068f8a7eSTamas Berghammer 105e85e6021STamas Berghammer #endif // defined(__arm__) 106e85e6021STamas Berghammer 107*b9c1b51eSKate Stone NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm( 108*b9c1b51eSKate Stone const ArchSpec &target_arch, NativeThreadProtocol &native_thread, 109*b9c1b51eSKate Stone uint32_t concrete_frame_idx) 110*b9c1b51eSKate Stone : NativeRegisterContextLinux(native_thread, concrete_frame_idx, 111*b9c1b51eSKate Stone new RegisterContextLinux_arm(target_arch)) { 112*b9c1b51eSKate Stone switch (target_arch.GetMachine()) { 1133f57216cSOmair Javaid case llvm::Triple::arm: 1143f57216cSOmair Javaid m_reg_info.num_registers = k_num_registers_arm; 1153f57216cSOmair Javaid m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; 1163f57216cSOmair Javaid m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; 1173f57216cSOmair Javaid m_reg_info.last_gpr = k_last_gpr_arm; 1183f57216cSOmair Javaid m_reg_info.first_fpr = k_first_fpr_arm; 1193f57216cSOmair Javaid m_reg_info.last_fpr = k_last_fpr_arm; 1203f57216cSOmair Javaid m_reg_info.first_fpr_v = fpu_s0_arm; 1213f57216cSOmair Javaid m_reg_info.last_fpr_v = fpu_s31_arm; 1223f57216cSOmair Javaid m_reg_info.gpr_flags = gpr_cpsr_arm; 1233f57216cSOmair Javaid break; 1243f57216cSOmair Javaid default: 1253f57216cSOmair Javaid assert(false && "Unhandled target architecture."); 1263f57216cSOmair Javaid break; 1273f57216cSOmair Javaid } 1283f57216cSOmair Javaid 1293f57216cSOmair Javaid ::memset(&m_fpr, 0, sizeof(m_fpr)); 1303f57216cSOmair Javaid ::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm)); 1312441aecdSOmair Javaid ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); 1322441aecdSOmair Javaid 1332441aecdSOmair Javaid // 16 is just a maximum value, query hardware for actual watchpoint count 1342441aecdSOmair Javaid m_max_hwp_supported = 16; 1352441aecdSOmair Javaid m_max_hbp_supported = 16; 1362441aecdSOmair Javaid m_refresh_hwdebug_info = true; 1373f57216cSOmair Javaid } 1383f57216cSOmair Javaid 139*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount() const { 1403f57216cSOmair Javaid return k_num_register_sets; 1413f57216cSOmair Javaid } 1423f57216cSOmair Javaid 143*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount() const { 1441f149204STamas Berghammer uint32_t count = 0; 1451f149204STamas Berghammer for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) 1461f149204STamas Berghammer count += g_reg_sets_arm[set_index].num_registers; 1471f149204STamas Berghammer return count; 1481f149204STamas Berghammer } 1491f149204STamas Berghammer 1503f57216cSOmair Javaid const RegisterSet * 151*b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index) const { 1523f57216cSOmair Javaid if (set_index < k_num_register_sets) 1533f57216cSOmair Javaid return &g_reg_sets_arm[set_index]; 1543f57216cSOmair Javaid 1553f57216cSOmair Javaid return nullptr; 1563f57216cSOmair Javaid } 1573f57216cSOmair Javaid 158*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ReadRegister(const RegisterInfo *reg_info, 159*b9c1b51eSKate Stone RegisterValue ®_value) { 1603f57216cSOmair Javaid Error error; 1613f57216cSOmair Javaid 162*b9c1b51eSKate 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 169*b9c1b51eSKate Stone if (IsFPR(reg)) { 170068f8a7eSTamas Berghammer error = ReadFPR(); 171068f8a7eSTamas Berghammer if (error.Fail()) 1723f57216cSOmair Javaid return error; 173*b9c1b51eSKate Stone } else { 1743f57216cSOmair Javaid uint32_t full_reg = reg; 175*b9c1b51eSKate Stone bool is_subreg = reg_info->invalidate_regs && 176*b9c1b51eSKate Stone (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 1773f57216cSOmair Javaid 178*b9c1b51eSKate 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 185*b9c1b51eSKate Stone if (error.Success()) { 186*b9c1b51eSKate Stone // If our read was not aligned (for ah,bh,ch,dh), shift our returned value 187*b9c1b51eSKate Stone // 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 191*b9c1b51eSKate Stone // If our return byte size was greater than the return value reg size, 192*b9c1b51eSKate Stone // then 1933f57216cSOmair Javaid // use the type specified by reg_info rather than the uint64_t 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; 204*b9c1b51eSKate 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."); 219*b9c1b51eSKate Stone error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, 220*b9c1b51eSKate Stone reg_info->byte_size); 2213f57216cSOmair Javaid break; 2223f57216cSOmair Javaid } 2233f57216cSOmair Javaid 2243f57216cSOmair Javaid return error; 2253f57216cSOmair Javaid } 2263f57216cSOmair Javaid 227*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::WriteRegister( 228*b9c1b51eSKate Stone const RegisterInfo *reg_info, const RegisterValue ®_value) { 2293f57216cSOmair Javaid if (!reg_info) 2303f57216cSOmair Javaid return Error("reg_info NULL"); 2313f57216cSOmair Javaid 2323f57216cSOmair Javaid const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 2333f57216cSOmair Javaid if (reg_index == LLDB_INVALID_REGNUM) 234*b9c1b51eSKate Stone return Error("no lldb regnum for %s", reg_info && reg_info->name 235*b9c1b51eSKate Stone ? reg_info->name 236*b9c1b51eSKate Stone : "<unknown register>"); 2373f57216cSOmair Javaid 2383f57216cSOmair Javaid if (IsGPR(reg_index)) 2393f57216cSOmair Javaid return WriteRegisterRaw(reg_index, reg_value); 2403f57216cSOmair Javaid 241*b9c1b51eSKate Stone if (IsFPR(reg_index)) { 2423f57216cSOmair Javaid // Get pointer to m_fpr variable and set the data to it. 243c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 244c40e7b17STamas Berghammer assert(fpr_offset < sizeof m_fpr); 245c40e7b17STamas Berghammer uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset; 246*b9c1b51eSKate Stone switch (reg_info->byte_size) { 2473f57216cSOmair Javaid case 2: 2483f57216cSOmair Javaid *(uint16_t *)dst = reg_value.GetAsUInt16(); 2493f57216cSOmair Javaid break; 2503f57216cSOmair Javaid case 4: 2513f57216cSOmair Javaid *(uint32_t *)dst = reg_value.GetAsUInt32(); 2523f57216cSOmair Javaid break; 2533f57216cSOmair Javaid case 8: 2543f57216cSOmair Javaid *(uint64_t *)dst = reg_value.GetAsUInt64(); 2553f57216cSOmair Javaid break; 2563f57216cSOmair Javaid default: 2573f57216cSOmair Javaid assert(false && "Unhandled data size."); 258*b9c1b51eSKate Stone return Error("unhandled register data size %" PRIu32, 259*b9c1b51eSKate Stone reg_info->byte_size); 2603f57216cSOmair Javaid } 2613f57216cSOmair Javaid 262068f8a7eSTamas Berghammer Error error = WriteFPR(); 263068f8a7eSTamas Berghammer if (error.Fail()) 264068f8a7eSTamas Berghammer return error; 2653f57216cSOmair Javaid 2663f57216cSOmair Javaid return Error(); 2673f57216cSOmair Javaid } 2683f57216cSOmair Javaid 269*b9c1b51eSKate Stone return Error("failed - register wasn't recognized to be a GPR or an FPR, " 270*b9c1b51eSKate Stone "write strategy unknown"); 2713f57216cSOmair Javaid } 2723f57216cSOmair Javaid 273*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ReadAllRegisterValues( 274*b9c1b51eSKate Stone lldb::DataBufferSP &data_sp) { 2753f57216cSOmair Javaid Error error; 2763f57216cSOmair Javaid 2773f57216cSOmair Javaid data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 2783f57216cSOmair Javaid if (!data_sp) 279*b9c1b51eSKate Stone return Error("failed to allocate DataBufferHeap instance of size %" PRIu64, 280*b9c1b51eSKate Stone (uint64_t)REG_CONTEXT_SIZE); 2813f57216cSOmair Javaid 282068f8a7eSTamas Berghammer error = ReadGPR(); 283068f8a7eSTamas Berghammer if (error.Fail()) 2843f57216cSOmair Javaid return error; 2853f57216cSOmair Javaid 286068f8a7eSTamas Berghammer error = ReadFPR(); 287068f8a7eSTamas Berghammer if (error.Fail()) 2883f57216cSOmair Javaid return error; 2893f57216cSOmair Javaid 2903f57216cSOmair Javaid uint8_t *dst = data_sp->GetBytes(); 291*b9c1b51eSKate Stone if (dst == nullptr) { 292*b9c1b51eSKate Stone error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 293*b9c1b51eSKate Stone " returned a null pointer", 294*b9c1b51eSKate Stone (uint64_t)REG_CONTEXT_SIZE); 2953f57216cSOmair Javaid return error; 2963f57216cSOmair Javaid } 2973f57216cSOmair Javaid 2983f57216cSOmair Javaid ::memcpy(dst, &m_gpr_arm, GetGPRSize()); 2993f57216cSOmair Javaid dst += GetGPRSize(); 3003f57216cSOmair Javaid ::memcpy(dst, &m_fpr, sizeof(m_fpr)); 3013f57216cSOmair Javaid 3023f57216cSOmair Javaid return error; 3033f57216cSOmair Javaid } 3043f57216cSOmair Javaid 305*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::WriteAllRegisterValues( 306*b9c1b51eSKate Stone const lldb::DataBufferSP &data_sp) { 3073f57216cSOmair Javaid Error error; 3083f57216cSOmair Javaid 309*b9c1b51eSKate Stone if (!data_sp) { 310*b9c1b51eSKate Stone error.SetErrorStringWithFormat( 311*b9c1b51eSKate Stone "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", 312*b9c1b51eSKate Stone __FUNCTION__); 3133f57216cSOmair Javaid return error; 3143f57216cSOmair Javaid } 3153f57216cSOmair Javaid 316*b9c1b51eSKate Stone if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 317*b9c1b51eSKate Stone error.SetErrorStringWithFormat( 318*b9c1b51eSKate Stone "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " 319*b9c1b51eSKate Stone "data size, expected %" PRIu64 ", actual %" PRIu64, 320*b9c1b51eSKate Stone __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize()); 3213f57216cSOmair Javaid return error; 3223f57216cSOmair Javaid } 3233f57216cSOmair Javaid 3243f57216cSOmair Javaid uint8_t *src = data_sp->GetBytes(); 325*b9c1b51eSKate Stone if (src == nullptr) { 326*b9c1b51eSKate Stone error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " 327*b9c1b51eSKate Stone "DataBuffer::GetBytes() returned a null " 328*b9c1b51eSKate Stone "pointer", 329*b9c1b51eSKate Stone __FUNCTION__); 3303f57216cSOmair Javaid return error; 3313f57216cSOmair Javaid } 3323f57216cSOmair Javaid ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize()); 3333f57216cSOmair Javaid 334068f8a7eSTamas Berghammer error = WriteGPR(); 335068f8a7eSTamas Berghammer if (error.Fail()) 3363f57216cSOmair Javaid return error; 3373f57216cSOmair Javaid 3383f57216cSOmair Javaid src += GetRegisterInfoInterface().GetGPRSize(); 3393f57216cSOmair Javaid ::memcpy(&m_fpr, src, sizeof(m_fpr)); 3403f57216cSOmair Javaid 341068f8a7eSTamas Berghammer error = WriteFPR(); 3423f57216cSOmair Javaid if (error.Fail()) 3433f57216cSOmair Javaid return error; 3443f57216cSOmair Javaid 3453f57216cSOmair Javaid return error; 3463f57216cSOmair Javaid } 3473f57216cSOmair Javaid 348*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const { 3493f57216cSOmair Javaid return reg <= m_reg_info.last_gpr; // GPR's come first. 3503f57216cSOmair Javaid } 3513f57216cSOmair Javaid 352*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const { 3533f57216cSOmair Javaid return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 3543f57216cSOmair Javaid } 3553f57216cSOmair Javaid 3562441aecdSOmair Javaid uint32_t 357*b9c1b51eSKate Stone NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr, 358*b9c1b51eSKate Stone size_t size) { 3592441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 3602441aecdSOmair Javaid 3612441aecdSOmair Javaid if (log) 3622441aecdSOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 3632441aecdSOmair Javaid 3642441aecdSOmair Javaid Error error; 3652441aecdSOmair Javaid 3662441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 3672441aecdSOmair Javaid error = ReadHardwareDebugInfo(); 3682441aecdSOmair Javaid 3692441aecdSOmair Javaid if (error.Fail()) 3702441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 3712441aecdSOmair Javaid 3722441aecdSOmair Javaid uint32_t control_value = 0, bp_index = 0; 3732441aecdSOmair Javaid 3742441aecdSOmair Javaid // Check if size has a valid hardware breakpoint length. 3752441aecdSOmair Javaid // Thumb instructions are 2-bytes but we have no way here to determine 3762441aecdSOmair Javaid // if target address is a thumb or arm instruction. 3772441aecdSOmair Javaid // TODO: Add support for setting thumb mode hardware breakpoints 3782441aecdSOmair Javaid if (size != 4 && size != 2) 3792441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 3802441aecdSOmair Javaid 3812441aecdSOmair Javaid // Setup control value 3822441aecdSOmair Javaid // Make the byte_mask into a valid Byte Address Select mask 3832441aecdSOmair Javaid control_value = 0xfu << 5; 3842441aecdSOmair Javaid 3852441aecdSOmair Javaid // Enable this breakpoint and make it stop in privileged or user mode; 3862441aecdSOmair Javaid control_value |= 7; 3872441aecdSOmair Javaid 3882441aecdSOmair Javaid // Make sure bits 1:0 are clear in our address 3892441aecdSOmair Javaid // This should be different once we support thumb here. 3902441aecdSOmair Javaid addr &= ~((lldb::addr_t)3); 3912441aecdSOmair Javaid 3922441aecdSOmair Javaid // Iterate over stored hardware breakpoints 3932441aecdSOmair Javaid // Find a free bp_index or update reference count if duplicate. 3942441aecdSOmair Javaid bp_index = LLDB_INVALID_INDEX32; 3952441aecdSOmair Javaid 396*b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 397*b9c1b51eSKate Stone if ((m_hbr_regs[i].control & 1) == 0) { 3982441aecdSOmair Javaid bp_index = i; // Mark last free slot 399*b9c1b51eSKate Stone } else if (m_hbr_regs[i].address == addr && 400*b9c1b51eSKate Stone m_hbr_regs[i].control == control_value) { 4012441aecdSOmair Javaid bp_index = i; // Mark duplicate index 4022441aecdSOmair Javaid break; // Stop searching here 4032441aecdSOmair Javaid } 4042441aecdSOmair Javaid } 4052441aecdSOmair Javaid 4062441aecdSOmair Javaid if (bp_index == LLDB_INVALID_INDEX32) 4072441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 4082441aecdSOmair Javaid 4094aa984c1SOmair Javaid // Add new or update existing breakpoint 410*b9c1b51eSKate Stone if ((m_hbr_regs[bp_index].control & 1) == 0) { 4112441aecdSOmair Javaid m_hbr_regs[bp_index].address = addr; 4122441aecdSOmair Javaid m_hbr_regs[bp_index].control = control_value; 4132441aecdSOmair Javaid m_hbr_regs[bp_index].refcount = 1; 4142441aecdSOmair Javaid 4152441aecdSOmair Javaid // PTRACE call to set corresponding hardware breakpoint register. 4162441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index); 4172441aecdSOmair Javaid 418*b9c1b51eSKate Stone if (error.Fail()) { 419d5510d1eSOmair Javaid m_hbr_regs[bp_index].address = 0; 420d5510d1eSOmair Javaid m_hbr_regs[bp_index].control &= ~1; 421d5510d1eSOmair Javaid m_hbr_regs[bp_index].refcount = 0; 422d5510d1eSOmair Javaid 4232441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 4242441aecdSOmair Javaid } 425*b9c1b51eSKate Stone } else 4262441aecdSOmair Javaid m_hbr_regs[bp_index].refcount++; 4272441aecdSOmair Javaid 4282441aecdSOmair Javaid return bp_index; 4292441aecdSOmair Javaid } 4302441aecdSOmair Javaid 431*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) { 4322441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 4332441aecdSOmair Javaid 4342441aecdSOmair Javaid if (log) 4352441aecdSOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 4362441aecdSOmair Javaid 4372441aecdSOmair Javaid Error error; 4382441aecdSOmair Javaid 4392441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 4402441aecdSOmair Javaid error = ReadHardwareDebugInfo(); 4412441aecdSOmair Javaid 4422441aecdSOmair Javaid if (error.Fail()) 4434aa984c1SOmair Javaid return false; 4442441aecdSOmair Javaid 4452441aecdSOmair Javaid if (hw_idx >= m_max_hbp_supported) 4462441aecdSOmair Javaid return false; 4472441aecdSOmair Javaid 4482441aecdSOmair Javaid // Update reference count if multiple references. 449*b9c1b51eSKate Stone if (m_hbr_regs[hw_idx].refcount > 1) { 4502441aecdSOmair Javaid m_hbr_regs[hw_idx].refcount--; 4512441aecdSOmair Javaid return true; 452*b9c1b51eSKate Stone } else if (m_hbr_regs[hw_idx].refcount == 1) { 453d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 454d5510d1eSOmair Javaid lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; 455d5510d1eSOmair Javaid uint32_t tempControl = m_hbr_regs[hw_idx].control; 456d5510d1eSOmair Javaid uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount; 457d5510d1eSOmair Javaid 4582441aecdSOmair Javaid m_hbr_regs[hw_idx].control &= ~1; 4592441aecdSOmair Javaid m_hbr_regs[hw_idx].address = 0; 4602441aecdSOmair Javaid m_hbr_regs[hw_idx].refcount = 0; 4612441aecdSOmair Javaid 4622441aecdSOmair Javaid // PTRACE call to clear corresponding hardware breakpoint register. 4632441aecdSOmair Javaid WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx); 4642441aecdSOmair Javaid 465*b9c1b51eSKate Stone if (error.Fail()) { 466d5510d1eSOmair Javaid m_hbr_regs[hw_idx].control = tempControl; 467d5510d1eSOmair Javaid m_hbr_regs[hw_idx].address = tempAddr; 468d5510d1eSOmair Javaid m_hbr_regs[hw_idx].refcount = tempRefCount; 469d5510d1eSOmair Javaid 4704aa984c1SOmair Javaid return false; 471d5510d1eSOmair Javaid } 4722441aecdSOmair Javaid 4732441aecdSOmair Javaid return true; 4742441aecdSOmair Javaid } 4752441aecdSOmair Javaid 4762441aecdSOmair Javaid return false; 4772441aecdSOmair Javaid } 4782441aecdSOmair Javaid 479*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() { 4802441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 4812441aecdSOmair Javaid 4822441aecdSOmair Javaid if (log) 4832441aecdSOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 4842441aecdSOmair Javaid 4852441aecdSOmair Javaid Error error; 4862441aecdSOmair Javaid 4872441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 4882441aecdSOmair Javaid error = ReadHardwareDebugInfo(); 4892441aecdSOmair Javaid 4902441aecdSOmair Javaid if (error.Fail()) 49162661473SOmair Javaid return 0; 4922441aecdSOmair Javaid 4932441aecdSOmair Javaid return m_max_hwp_supported; 4942441aecdSOmair Javaid } 4952441aecdSOmair Javaid 496*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint( 497*b9c1b51eSKate Stone lldb::addr_t addr, size_t size, uint32_t watch_flags) { 4982441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 4992441aecdSOmair Javaid 5002441aecdSOmair Javaid if (log) 5012441aecdSOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 5022441aecdSOmair Javaid 5032441aecdSOmair Javaid Error error; 5042441aecdSOmair Javaid 5052441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 5062441aecdSOmair Javaid error = ReadHardwareDebugInfo(); 5072441aecdSOmair Javaid 5082441aecdSOmair Javaid if (error.Fail()) 5092441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5102441aecdSOmair Javaid 5112441aecdSOmair Javaid uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0; 512c6dc90efSOmair Javaid lldb::addr_t real_addr = addr; 5132441aecdSOmair Javaid 5142441aecdSOmair Javaid // Check if we are setting watchpoint other than read/write/access 5152441aecdSOmair Javaid // Also update watchpoint flag to match Arm write-read bit configuration. 516*b9c1b51eSKate Stone switch (watch_flags) { 5172441aecdSOmair Javaid case 1: 5182441aecdSOmair Javaid watch_flags = 2; 5192441aecdSOmair Javaid break; 5202441aecdSOmair Javaid case 2: 5212441aecdSOmair Javaid watch_flags = 1; 5222441aecdSOmair Javaid break; 5232441aecdSOmair Javaid case 3: 5242441aecdSOmair Javaid break; 5252441aecdSOmair Javaid default: 5262441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5272441aecdSOmair Javaid } 5282441aecdSOmair Javaid 5292441aecdSOmair Javaid // Can't watch zero bytes 5302441aecdSOmair Javaid // Can't watch more than 4 bytes per WVR/WCR pair 5312441aecdSOmair Javaid 5322441aecdSOmair Javaid if (size == 0 || size > 4) 5332441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5342441aecdSOmair Javaid 535c6dc90efSOmair Javaid // Check 4-byte alignment for hardware watchpoint target address. 536c6dc90efSOmair Javaid // Below is a hack to recalculate address and size in order to 537c6dc90efSOmair Javaid // make sure we can watch non 4-byte alligned addresses as well. 538*b9c1b51eSKate Stone if (addr & 0x03) { 539c6dc90efSOmair Javaid uint8_t watch_mask = (addr & 0x03) + size; 540c6dc90efSOmair Javaid 541c6dc90efSOmair Javaid if (watch_mask > 0x04) 542c6dc90efSOmair Javaid return LLDB_INVALID_INDEX32; 543c6dc90efSOmair Javaid else if (watch_mask <= 0x02) 544c6dc90efSOmair Javaid size = 2; 545c6dc90efSOmair Javaid else if (watch_mask <= 0x04) 546c6dc90efSOmair Javaid size = 4; 547c6dc90efSOmair Javaid 548c6dc90efSOmair Javaid addr = addr & (~0x03); 549c6dc90efSOmair Javaid } 550c6dc90efSOmair Javaid 5512441aecdSOmair Javaid // We can only watch up to four bytes that follow a 4 byte aligned address 5522441aecdSOmair Javaid // per watchpoint register pair, so make sure we can properly encode this. 5532441aecdSOmair Javaid addr_word_offset = addr % 4; 5542441aecdSOmair Javaid byte_mask = ((1u << size) - 1u) << addr_word_offset; 5552441aecdSOmair Javaid 5562441aecdSOmair Javaid // Check if we need multiple watchpoint register 5572441aecdSOmair Javaid if (byte_mask > 0xfu) 5582441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5592441aecdSOmair Javaid 5602441aecdSOmair Javaid // Setup control value 5612441aecdSOmair Javaid // Make the byte_mask into a valid Byte Address Select mask 5622441aecdSOmair Javaid control_value = byte_mask << 5; 5632441aecdSOmair Javaid 5642441aecdSOmair Javaid // Turn on appropriate watchpoint flags read or write 5652441aecdSOmair Javaid control_value |= (watch_flags << 3); 5662441aecdSOmair Javaid 5672441aecdSOmair Javaid // Enable this watchpoint and make it stop in privileged or user mode; 5682441aecdSOmair Javaid control_value |= 7; 5692441aecdSOmair Javaid 5702441aecdSOmair Javaid // Make sure bits 1:0 are clear in our address 5712441aecdSOmair Javaid addr &= ~((lldb::addr_t)3); 5722441aecdSOmair Javaid 5732441aecdSOmair Javaid // Iterate over stored watchpoints 5742441aecdSOmair Javaid // Find a free wp_index or update reference count if duplicate. 5752441aecdSOmair Javaid wp_index = LLDB_INVALID_INDEX32; 576*b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 577*b9c1b51eSKate Stone if ((m_hwp_regs[i].control & 1) == 0) { 5782441aecdSOmair Javaid wp_index = i; // Mark last free slot 579*b9c1b51eSKate Stone } else if (m_hwp_regs[i].address == addr && 580*b9c1b51eSKate Stone m_hwp_regs[i].control == control_value) { 5812441aecdSOmair Javaid wp_index = i; // Mark duplicate index 5822441aecdSOmair Javaid break; // Stop searching here 5832441aecdSOmair Javaid } 5842441aecdSOmair Javaid } 5852441aecdSOmair Javaid 5862441aecdSOmair Javaid if (wp_index == LLDB_INVALID_INDEX32) 5872441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5882441aecdSOmair Javaid 5892441aecdSOmair Javaid // Add new or update existing watchpoint 590*b9c1b51eSKate Stone if ((m_hwp_regs[wp_index].control & 1) == 0) { 5912441aecdSOmair Javaid // Update watchpoint in local cache 592c6dc90efSOmair Javaid m_hwp_regs[wp_index].real_addr = real_addr; 5932441aecdSOmair Javaid m_hwp_regs[wp_index].address = addr; 5942441aecdSOmair Javaid m_hwp_regs[wp_index].control = control_value; 5952441aecdSOmair Javaid m_hwp_regs[wp_index].refcount = 1; 5962441aecdSOmair Javaid 5972441aecdSOmair Javaid // PTRACE call to set corresponding watchpoint register. 5982441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); 5992441aecdSOmair Javaid 600*b9c1b51eSKate Stone if (error.Fail()) { 601d5510d1eSOmair Javaid m_hwp_regs[wp_index].address = 0; 602d5510d1eSOmair Javaid m_hwp_regs[wp_index].control &= ~1; 603d5510d1eSOmair Javaid m_hwp_regs[wp_index].refcount = 0; 604d5510d1eSOmair Javaid 6052441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 6062441aecdSOmair Javaid } 607*b9c1b51eSKate Stone } else 6082441aecdSOmair Javaid m_hwp_regs[wp_index].refcount++; 6092441aecdSOmair Javaid 6102441aecdSOmair Javaid return wp_index; 6112441aecdSOmair Javaid } 6122441aecdSOmair Javaid 613*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint( 614*b9c1b51eSKate Stone uint32_t wp_index) { 6152441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 6162441aecdSOmair Javaid 6172441aecdSOmair Javaid if (log) 6182441aecdSOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 6192441aecdSOmair Javaid 6202441aecdSOmair Javaid Error error; 6212441aecdSOmair Javaid 6222441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 6232441aecdSOmair Javaid error = ReadHardwareDebugInfo(); 6242441aecdSOmair Javaid 6252441aecdSOmair Javaid if (error.Fail()) 6264aa984c1SOmair Javaid return false; 6272441aecdSOmair Javaid 6282441aecdSOmair Javaid if (wp_index >= m_max_hwp_supported) 6292441aecdSOmair Javaid return false; 6302441aecdSOmair Javaid 6312441aecdSOmair Javaid // Update reference count if multiple references. 632*b9c1b51eSKate Stone if (m_hwp_regs[wp_index].refcount > 1) { 6332441aecdSOmair Javaid m_hwp_regs[wp_index].refcount--; 6342441aecdSOmair Javaid return true; 635*b9c1b51eSKate Stone } else if (m_hwp_regs[wp_index].refcount == 1) { 636d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 637d5510d1eSOmair Javaid lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 638d5510d1eSOmair Javaid uint32_t tempControl = m_hwp_regs[wp_index].control; 639d5510d1eSOmair Javaid uint32_t tempRefCount = m_hwp_regs[wp_index].refcount; 640d5510d1eSOmair Javaid 6412441aecdSOmair Javaid // Update watchpoint in local cache 6422441aecdSOmair Javaid m_hwp_regs[wp_index].control &= ~1; 6432441aecdSOmair Javaid m_hwp_regs[wp_index].address = 0; 6442441aecdSOmair Javaid m_hwp_regs[wp_index].refcount = 0; 6452441aecdSOmair Javaid 6462441aecdSOmair Javaid // Ptrace call to update hardware debug registers 6472441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); 6482441aecdSOmair Javaid 649*b9c1b51eSKate Stone if (error.Fail()) { 650d5510d1eSOmair Javaid m_hwp_regs[wp_index].control = tempControl; 651d5510d1eSOmair Javaid m_hwp_regs[wp_index].address = tempAddr; 652d5510d1eSOmair Javaid m_hwp_regs[wp_index].refcount = tempRefCount; 653d5510d1eSOmair Javaid 6542441aecdSOmair Javaid return false; 655d5510d1eSOmair Javaid } 6562441aecdSOmair Javaid 6572441aecdSOmair Javaid return true; 6582441aecdSOmair Javaid } 6592441aecdSOmair Javaid 6602441aecdSOmair Javaid return false; 6612441aecdSOmair Javaid } 6622441aecdSOmair Javaid 663*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() { 6642441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 6652441aecdSOmair Javaid 6662441aecdSOmair Javaid if (log) 6672441aecdSOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 6682441aecdSOmair Javaid 6692441aecdSOmair Javaid Error error; 6702441aecdSOmair Javaid 6712441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 6722441aecdSOmair Javaid error = ReadHardwareDebugInfo(); 6732441aecdSOmair Javaid 6742441aecdSOmair Javaid if (error.Fail()) 6752441aecdSOmair Javaid return error; 6762441aecdSOmair Javaid 677d5510d1eSOmair Javaid lldb::addr_t tempAddr = 0; 678d5510d1eSOmair Javaid uint32_t tempControl = 0, tempRefCount = 0; 679d5510d1eSOmair Javaid 680*b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 681*b9c1b51eSKate Stone if (m_hwp_regs[i].control & 0x01) { 682d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 683d5510d1eSOmair Javaid tempAddr = m_hwp_regs[i].address; 684d5510d1eSOmair Javaid tempControl = m_hwp_regs[i].control; 685d5510d1eSOmair Javaid tempRefCount = m_hwp_regs[i].refcount; 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 m_hwp_regs[i].refcount = 0; 6912441aecdSOmair Javaid 6922441aecdSOmair Javaid // Ptrace call to update hardware debug registers 6932441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, i); 6942441aecdSOmair Javaid 695*b9c1b51eSKate Stone if (error.Fail()) { 696d5510d1eSOmair Javaid m_hwp_regs[i].control = tempControl; 697d5510d1eSOmair Javaid m_hwp_regs[i].address = tempAddr; 698d5510d1eSOmair Javaid m_hwp_regs[i].refcount = tempRefCount; 699d5510d1eSOmair Javaid 7002441aecdSOmair Javaid return error; 7012441aecdSOmair Javaid } 7022441aecdSOmair Javaid } 703d5510d1eSOmair Javaid } 7042441aecdSOmair Javaid 7052441aecdSOmair Javaid return Error(); 7062441aecdSOmair Javaid } 7072441aecdSOmair Javaid 708*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) { 7092441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 7102441aecdSOmair Javaid 7112441aecdSOmair Javaid if (log) 7122441aecdSOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 7132441aecdSOmair Javaid 714*b9c1b51eSKate Stone switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) { 7152441aecdSOmair Javaid case 0x01: 7162441aecdSOmair Javaid return 1; 7172441aecdSOmair Javaid case 0x03: 7182441aecdSOmair Javaid return 2; 7192441aecdSOmair Javaid case 0x07: 7202441aecdSOmair Javaid return 3; 7212441aecdSOmair Javaid case 0x0f: 7222441aecdSOmair Javaid return 4; 7232441aecdSOmair Javaid default: 7242441aecdSOmair Javaid return 0; 7252441aecdSOmair Javaid } 7262441aecdSOmair Javaid } 727*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) { 7282441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 7292441aecdSOmair Javaid 7302441aecdSOmair Javaid if (log) 7312441aecdSOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 7322441aecdSOmair Javaid 7332441aecdSOmair Javaid if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 7342441aecdSOmair Javaid return true; 7352441aecdSOmair Javaid else 7362441aecdSOmair Javaid return false; 7372441aecdSOmair Javaid } 7382441aecdSOmair Javaid 739*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::GetWatchpointHitIndex( 740*b9c1b51eSKate Stone uint32_t &wp_index, lldb::addr_t trap_addr) { 7412441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 7422441aecdSOmair Javaid 7432441aecdSOmair Javaid if (log) 7442441aecdSOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 7452441aecdSOmair Javaid 7462441aecdSOmair Javaid uint32_t watch_size; 7472441aecdSOmair Javaid lldb::addr_t watch_addr; 7482441aecdSOmair Javaid 749*b9c1b51eSKate Stone for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { 7502441aecdSOmair Javaid watch_size = GetWatchpointSize(wp_index); 7512441aecdSOmair Javaid watch_addr = m_hwp_regs[wp_index].address; 7522441aecdSOmair Javaid 753*b9c1b51eSKate Stone if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) && 754*b9c1b51eSKate Stone trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) { 755c6dc90efSOmair Javaid m_hwp_regs[wp_index].hit_addr = trap_addr; 7562441aecdSOmair Javaid return Error(); 7572441aecdSOmair Javaid } 7582441aecdSOmair Javaid } 7592441aecdSOmair Javaid 7602441aecdSOmair Javaid wp_index = LLDB_INVALID_INDEX32; 7612441aecdSOmair Javaid return Error(); 7622441aecdSOmair Javaid } 7632441aecdSOmair Javaid 7642441aecdSOmair Javaid lldb::addr_t 765*b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) { 7662441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 7672441aecdSOmair Javaid 7682441aecdSOmair Javaid if (log) 7692441aecdSOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 7702441aecdSOmair Javaid 7712441aecdSOmair Javaid if (wp_index >= m_max_hwp_supported) 7722441aecdSOmair Javaid return LLDB_INVALID_ADDRESS; 7732441aecdSOmair Javaid 7742441aecdSOmair Javaid if (WatchpointIsEnabled(wp_index)) 775c6dc90efSOmair Javaid return m_hwp_regs[wp_index].real_addr; 776c6dc90efSOmair Javaid else 777c6dc90efSOmair Javaid return LLDB_INVALID_ADDRESS; 778c6dc90efSOmair Javaid } 779c6dc90efSOmair Javaid 780c6dc90efSOmair Javaid lldb::addr_t 781*b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) { 782c6dc90efSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); 783c6dc90efSOmair Javaid 784c6dc90efSOmair Javaid if (log) 785c6dc90efSOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 786c6dc90efSOmair Javaid 787c6dc90efSOmair Javaid if (wp_index >= m_max_hwp_supported) 788c6dc90efSOmair Javaid return LLDB_INVALID_ADDRESS; 789c6dc90efSOmair Javaid 790c6dc90efSOmair Javaid if (WatchpointIsEnabled(wp_index)) 791c6dc90efSOmair Javaid return m_hwp_regs[wp_index].hit_addr; 7922441aecdSOmair Javaid else 7932441aecdSOmair Javaid return LLDB_INVALID_ADDRESS; 7942441aecdSOmair Javaid } 7952441aecdSOmair Javaid 796*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() { 7972441aecdSOmair Javaid Error error; 7982441aecdSOmair Javaid 799*b9c1b51eSKate Stone if (!m_refresh_hwdebug_info) { 8002441aecdSOmair Javaid return Error(); 8012441aecdSOmair Javaid } 8022441aecdSOmair Javaid 8032441aecdSOmair Javaid unsigned int cap_val; 8042441aecdSOmair Javaid 805*b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), 806*b9c1b51eSKate Stone nullptr, &cap_val, 807*b9c1b51eSKate Stone sizeof(unsigned int)); 8082441aecdSOmair Javaid 8092441aecdSOmair Javaid if (error.Fail()) 8102441aecdSOmair Javaid return error; 8112441aecdSOmair Javaid 8122441aecdSOmair Javaid m_max_hwp_supported = (cap_val >> 8) & 0xff; 8132441aecdSOmair Javaid m_max_hbp_supported = cap_val & 0xff; 8142441aecdSOmair Javaid m_refresh_hwdebug_info = false; 8152441aecdSOmair Javaid 8162441aecdSOmair Javaid return error; 8172441aecdSOmair Javaid } 8182441aecdSOmair Javaid 819*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, 820*b9c1b51eSKate Stone int hwb_index) { 8212441aecdSOmair Javaid Error error; 8222441aecdSOmair Javaid 8232441aecdSOmair Javaid lldb::addr_t *addr_buf; 8242441aecdSOmair Javaid uint32_t *ctrl_buf; 8252441aecdSOmair Javaid 826*b9c1b51eSKate Stone if (hwbType == eDREGTypeWATCH) { 8272441aecdSOmair Javaid addr_buf = &m_hwp_regs[hwb_index].address; 8282441aecdSOmair Javaid ctrl_buf = &m_hwp_regs[hwb_index].control; 8292441aecdSOmair Javaid 830*b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 831*b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 832*b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf, 833*b9c1b51eSKate Stone sizeof(unsigned int)); 8342441aecdSOmair Javaid 8352441aecdSOmair Javaid if (error.Fail()) 8362441aecdSOmair Javaid return error; 8372441aecdSOmair Javaid 838*b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 839*b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 840*b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf, 841*b9c1b51eSKate Stone sizeof(unsigned int)); 842*b9c1b51eSKate Stone } else { 8432441aecdSOmair Javaid addr_buf = &m_hwp_regs[hwb_index].address; 8442441aecdSOmair Javaid ctrl_buf = &m_hwp_regs[hwb_index].control; 8452441aecdSOmair Javaid 846*b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 847*b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 848*b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf, 849*b9c1b51eSKate Stone sizeof(unsigned int)); 8502441aecdSOmair Javaid 8512441aecdSOmair Javaid if (error.Fail()) 8522441aecdSOmair Javaid return error; 8532441aecdSOmair Javaid 854*b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 855*b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 856*b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf, 857*b9c1b51eSKate Stone sizeof(unsigned int)); 8582441aecdSOmair Javaid } 8592441aecdSOmair Javaid 8602441aecdSOmair Javaid return error; 8612441aecdSOmair Javaid } 862c40e7b17STamas Berghammer 863*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset( 864*b9c1b51eSKate Stone const RegisterInfo *reg_info) const { 865*b9c1b51eSKate Stone return reg_info->byte_offset - 866*b9c1b51eSKate Stone GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; 867c40e7b17STamas Berghammer } 868c40e7b17STamas Berghammer 869*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoReadRegisterValue( 870*b9c1b51eSKate Stone uint32_t offset, const char *reg_name, uint32_t size, 871*b9c1b51eSKate Stone RegisterValue &value) { 872*b9c1b51eSKate Stone // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android 873*b9c1b51eSKate Stone // devices (always return 874*b9c1b51eSKate Stone // "Bad address"). To avoid using PTRACE_PEEKUSER we read out the full GPR 875*b9c1b51eSKate Stone // register set instead. 876*b9c1b51eSKate Stone // This approach is about 4 times slower but the performance overhead is 877*b9c1b51eSKate Stone // negligible in 878e85e6021STamas Berghammer // comparision to processing time in lldb-server. 879e85e6021STamas Berghammer assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); 880e85e6021STamas Berghammer if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) 881e85e6021STamas Berghammer return Error("Register isn't fit into the size of the GPR area"); 882e85e6021STamas Berghammer 883e85e6021STamas Berghammer Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm)); 884e85e6021STamas Berghammer if (error.Fail()) 885e85e6021STamas Berghammer return error; 886e85e6021STamas Berghammer 887e85e6021STamas Berghammer value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]); 888e85e6021STamas Berghammer return Error(); 889e85e6021STamas Berghammer } 890e85e6021STamas Berghammer 891*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoWriteRegisterValue( 892*b9c1b51eSKate Stone uint32_t offset, const char *reg_name, const RegisterValue &value) { 893*b9c1b51eSKate Stone // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android 894*b9c1b51eSKate Stone // devices (always return 895*b9c1b51eSKate Stone // "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR 896*b9c1b51eSKate Stone // register set, modify 897*b9c1b51eSKate Stone // the requested register and write it back. This approach is about 4 times 898*b9c1b51eSKate Stone // slower but the 899*b9c1b51eSKate Stone // performance overhead is negligible in comparision to processing time in 900*b9c1b51eSKate Stone // lldb-server. 901ce26b7a6STamas Berghammer assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); 902ce26b7a6STamas Berghammer if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) 903ce26b7a6STamas Berghammer return Error("Register isn't fit into the size of the GPR area"); 904ce26b7a6STamas Berghammer 905ce26b7a6STamas Berghammer Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm)); 906ce26b7a6STamas Berghammer if (error.Fail()) 907ce26b7a6STamas Berghammer return error; 908ce26b7a6STamas Berghammer 909a7d7f7cfSOmair Javaid uint32_t reg_value = value.GetAsUInt32(); 910a7d7f7cfSOmair Javaid // As precaution for an undefined behavior encountered while setting PC we 911a7d7f7cfSOmair Javaid // will clear thumb bit of new PC if we are already in thumb mode; that is 912a7d7f7cfSOmair Javaid // CPSR thumb mode bit is set. 913*b9c1b51eSKate Stone if (offset / sizeof(uint32_t) == gpr_pc_arm) { 914a7d7f7cfSOmair Javaid // Check if we are already in thumb mode and 915a7d7f7cfSOmair Javaid // thumb bit of current PC is read out to be zero and 916a7d7f7cfSOmair Javaid // thumb bit of next PC is read out to be one. 917*b9c1b51eSKate Stone if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) && 918*b9c1b51eSKate Stone (value.GetAsUInt32() & 0x01)) { 919a7d7f7cfSOmair Javaid reg_value &= (~1ull); 920a7d7f7cfSOmair Javaid } 921a7d7f7cfSOmair Javaid } 922a7d7f7cfSOmair Javaid 923a7d7f7cfSOmair Javaid m_gpr_arm[offset / sizeof(uint32_t)] = reg_value; 924ce26b7a6STamas Berghammer return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm)); 925ce26b7a6STamas Berghammer } 926ce26b7a6STamas Berghammer 927*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoReadGPR(void *buf, size_t buf_size) { 928e85e6021STamas Berghammer #ifdef __arm__ 929e85e6021STamas Berghammer return NativeRegisterContextLinux::DoReadGPR(buf, buf_size); 930e85e6021STamas Berghammer #else // __aarch64__ 931e85e6021STamas Berghammer struct iovec ioVec; 932e85e6021STamas Berghammer ioVec.iov_base = buf; 933e85e6021STamas Berghammer ioVec.iov_len = buf_size; 934e85e6021STamas Berghammer 935e85e6021STamas Berghammer return ReadRegisterSet(&ioVec, buf_size, NT_PRSTATUS); 936e85e6021STamas Berghammer #endif // __arm__ 937e85e6021STamas Berghammer } 938e85e6021STamas Berghammer 939*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoWriteGPR(void *buf, size_t buf_size) { 940e85e6021STamas Berghammer #ifdef __arm__ 941e85e6021STamas Berghammer return NativeRegisterContextLinux::DoWriteGPR(buf, buf_size); 942e85e6021STamas Berghammer #else // __aarch64__ 943e85e6021STamas Berghammer struct iovec ioVec; 944e85e6021STamas Berghammer ioVec.iov_base = buf; 945e85e6021STamas Berghammer ioVec.iov_len = buf_size; 946e85e6021STamas Berghammer 947e85e6021STamas Berghammer return WriteRegisterSet(&ioVec, buf_size, NT_PRSTATUS); 948e85e6021STamas Berghammer #endif // __arm__ 949e85e6021STamas Berghammer } 950e85e6021STamas Berghammer 951*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size) { 952e85e6021STamas Berghammer #ifdef __arm__ 953*b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(), 954*b9c1b51eSKate Stone nullptr, buf, buf_size); 955e85e6021STamas Berghammer #else // __aarch64__ 956e85e6021STamas Berghammer struct iovec ioVec; 957e85e6021STamas Berghammer ioVec.iov_base = buf; 958e85e6021STamas Berghammer ioVec.iov_len = buf_size; 959e85e6021STamas Berghammer 960e85e6021STamas Berghammer return ReadRegisterSet(&ioVec, buf_size, NT_ARM_VFP); 961e85e6021STamas Berghammer #endif // __arm__ 962ce26b7a6STamas Berghammer } 963ce26b7a6STamas Berghammer 964*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size) { 965e85e6021STamas Berghammer #ifdef __arm__ 966*b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(), 967*b9c1b51eSKate Stone nullptr, buf, buf_size); 968e85e6021STamas Berghammer #else // __aarch64__ 969e85e6021STamas Berghammer struct iovec ioVec; 970e85e6021STamas Berghammer ioVec.iov_base = buf; 971e85e6021STamas Berghammer ioVec.iov_len = buf_size; 972e85e6021STamas Berghammer 973e85e6021STamas Berghammer return WriteRegisterSet(&ioVec, buf_size, NT_ARM_VFP); 974e85e6021STamas Berghammer #endif // __arm__ 975ce26b7a6STamas Berghammer } 976ce26b7a6STamas Berghammer 977e85e6021STamas Berghammer #endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 978