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" 152441aecdSOmair Javaid #include "lldb/Core/Log.h" 163f57216cSOmair Javaid #include "lldb/Core/RegisterValue.h" 17bf9a7730SZachary Turner #include "lldb/Utility/Error.h" 18068f8a7eSTamas Berghammer 19e85e6021STamas Berghammer #include "Plugins/Process/Linux/Procfs.h" 20ea1b6b17SPavel Labath #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 21068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_arm.h" 223f57216cSOmair Javaid 23e85e6021STamas Berghammer #include <elf.h> 24e85e6021STamas Berghammer #include <sys/socket.h> 25e85e6021STamas Berghammer 263f57216cSOmair Javaid #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr)) 273f57216cSOmair Javaid 28ce26b7a6STamas Berghammer #ifndef PTRACE_GETVFPREGS 29ce26b7a6STamas Berghammer #define PTRACE_GETVFPREGS 27 30ce26b7a6STamas Berghammer #define PTRACE_SETVFPREGS 28 31ce26b7a6STamas Berghammer #endif 322441aecdSOmair Javaid #ifndef PTRACE_GETHBPREGS 332441aecdSOmair Javaid #define PTRACE_GETHBPREGS 29 342441aecdSOmair Javaid #define PTRACE_SETHBPREGS 30 352441aecdSOmair Javaid #endif 362441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG3) 372441aecdSOmair Javaid #define PTRACE_TYPE_ARG3 void * 382441aecdSOmair Javaid #endif 392441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG4) 402441aecdSOmair Javaid #define PTRACE_TYPE_ARG4 void * 412441aecdSOmair Javaid #endif 422441aecdSOmair Javaid 433f57216cSOmair Javaid using namespace lldb; 443f57216cSOmair Javaid using namespace lldb_private; 453f57216cSOmair Javaid using namespace lldb_private::process_linux; 463f57216cSOmair Javaid 473f57216cSOmair Javaid // arm general purpose registers. 48b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_arm[] = { 49b9c1b51eSKate Stone gpr_r0_arm, gpr_r1_arm, gpr_r2_arm, gpr_r3_arm, gpr_r4_arm, 50b9c1b51eSKate Stone gpr_r5_arm, gpr_r6_arm, gpr_r7_arm, gpr_r8_arm, gpr_r9_arm, 51b9c1b51eSKate Stone gpr_r10_arm, gpr_r11_arm, gpr_r12_arm, gpr_sp_arm, gpr_lr_arm, 52b9c1b51eSKate Stone gpr_pc_arm, gpr_cpsr_arm, 533f57216cSOmair Javaid LLDB_INVALID_REGNUM // register sets need to end with this flag 543f57216cSOmair Javaid }; 55b9c1b51eSKate Stone static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == 56b9c1b51eSKate Stone k_num_gpr_registers_arm, 573f57216cSOmair Javaid "g_gpr_regnums_arm has wrong number of register infos"); 583f57216cSOmair Javaid 593f57216cSOmair Javaid // arm floating point registers. 60b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_arm[] = { 61b9c1b51eSKate Stone fpu_s0_arm, fpu_s1_arm, fpu_s2_arm, fpu_s3_arm, fpu_s4_arm, 62b9c1b51eSKate Stone fpu_s5_arm, fpu_s6_arm, fpu_s7_arm, fpu_s8_arm, fpu_s9_arm, 63b9c1b51eSKate Stone fpu_s10_arm, fpu_s11_arm, fpu_s12_arm, fpu_s13_arm, fpu_s14_arm, 64b9c1b51eSKate Stone fpu_s15_arm, fpu_s16_arm, fpu_s17_arm, fpu_s18_arm, fpu_s19_arm, 65b9c1b51eSKate Stone fpu_s20_arm, fpu_s21_arm, fpu_s22_arm, fpu_s23_arm, fpu_s24_arm, 66b9c1b51eSKate Stone fpu_s25_arm, fpu_s26_arm, fpu_s27_arm, fpu_s28_arm, fpu_s29_arm, 67b9c1b51eSKate Stone fpu_s30_arm, fpu_s31_arm, fpu_fpscr_arm, fpu_d0_arm, fpu_d1_arm, 68b9c1b51eSKate Stone fpu_d2_arm, fpu_d3_arm, fpu_d4_arm, fpu_d5_arm, fpu_d6_arm, 69b9c1b51eSKate Stone fpu_d7_arm, fpu_d8_arm, fpu_d9_arm, fpu_d10_arm, fpu_d11_arm, 70b9c1b51eSKate Stone fpu_d12_arm, fpu_d13_arm, fpu_d14_arm, fpu_d15_arm, fpu_d16_arm, 71b9c1b51eSKate Stone fpu_d17_arm, fpu_d18_arm, fpu_d19_arm, fpu_d20_arm, fpu_d21_arm, 72b9c1b51eSKate Stone fpu_d22_arm, fpu_d23_arm, fpu_d24_arm, fpu_d25_arm, fpu_d26_arm, 73b9c1b51eSKate Stone fpu_d27_arm, fpu_d28_arm, fpu_d29_arm, fpu_d30_arm, fpu_d31_arm, 74b9c1b51eSKate Stone fpu_q0_arm, fpu_q1_arm, fpu_q2_arm, fpu_q3_arm, fpu_q4_arm, 75b9c1b51eSKate Stone fpu_q5_arm, fpu_q6_arm, fpu_q7_arm, fpu_q8_arm, fpu_q9_arm, 76b9c1b51eSKate Stone fpu_q10_arm, fpu_q11_arm, fpu_q12_arm, fpu_q13_arm, fpu_q14_arm, 77b4e95a50STamas Berghammer fpu_q15_arm, 783f57216cSOmair Javaid LLDB_INVALID_REGNUM // register sets need to end with this flag 793f57216cSOmair Javaid }; 80b9c1b51eSKate Stone static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == 81b9c1b51eSKate Stone k_num_fpr_registers_arm, 823f57216cSOmair Javaid "g_fpu_regnums_arm has wrong number of register infos"); 833f57216cSOmair Javaid 843f57216cSOmair Javaid namespace { 853f57216cSOmair Javaid // Number of register sets provided by this context. 86b9c1b51eSKate Stone enum { k_num_register_sets = 2 }; 873f57216cSOmair Javaid } 883f57216cSOmair Javaid 893f57216cSOmair Javaid // Register sets for arm. 90b9c1b51eSKate Stone static const RegisterSet g_reg_sets_arm[k_num_register_sets] = { 91b9c1b51eSKate Stone {"General Purpose Registers", "gpr", k_num_gpr_registers_arm, 92b9c1b51eSKate Stone g_gpr_regnums_arm}, 93b9c1b51eSKate Stone {"Floating Point Registers", "fpu", k_num_fpr_registers_arm, 94b9c1b51eSKate Stone g_fpu_regnums_arm}}; 953f57216cSOmair Javaid 96e85e6021STamas Berghammer #if defined(__arm__) 97e85e6021STamas Berghammer 98068f8a7eSTamas Berghammer NativeRegisterContextLinux * 99b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 100b9c1b51eSKate Stone const ArchSpec &target_arch, NativeThreadProtocol &native_thread, 101b9c1b51eSKate Stone uint32_t concrete_frame_idx) { 102b9c1b51eSKate Stone return new NativeRegisterContextLinux_arm(target_arch, native_thread, 103b9c1b51eSKate Stone concrete_frame_idx); 104068f8a7eSTamas Berghammer } 105068f8a7eSTamas Berghammer 106e85e6021STamas Berghammer #endif // defined(__arm__) 107e85e6021STamas Berghammer 108b9c1b51eSKate Stone NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm( 109b9c1b51eSKate Stone const ArchSpec &target_arch, NativeThreadProtocol &native_thread, 110b9c1b51eSKate Stone uint32_t concrete_frame_idx) 111b9c1b51eSKate Stone : NativeRegisterContextLinux(native_thread, concrete_frame_idx, 112b9c1b51eSKate Stone new RegisterContextLinux_arm(target_arch)) { 113b9c1b51eSKate Stone switch (target_arch.GetMachine()) { 1143f57216cSOmair Javaid case llvm::Triple::arm: 1153f57216cSOmair Javaid m_reg_info.num_registers = k_num_registers_arm; 1163f57216cSOmair Javaid m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; 1173f57216cSOmair Javaid m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; 1183f57216cSOmair Javaid m_reg_info.last_gpr = k_last_gpr_arm; 1193f57216cSOmair Javaid m_reg_info.first_fpr = k_first_fpr_arm; 1203f57216cSOmair Javaid m_reg_info.last_fpr = k_last_fpr_arm; 1213f57216cSOmair Javaid m_reg_info.first_fpr_v = fpu_s0_arm; 1223f57216cSOmair Javaid m_reg_info.last_fpr_v = fpu_s31_arm; 1233f57216cSOmair Javaid m_reg_info.gpr_flags = gpr_cpsr_arm; 1243f57216cSOmair Javaid break; 1253f57216cSOmair Javaid default: 1263f57216cSOmair Javaid assert(false && "Unhandled target architecture."); 1273f57216cSOmair Javaid break; 1283f57216cSOmair Javaid } 1293f57216cSOmair Javaid 1303f57216cSOmair Javaid ::memset(&m_fpr, 0, sizeof(m_fpr)); 1313f57216cSOmair Javaid ::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm)); 1322441aecdSOmair Javaid ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); 133*d5ffbad2SOmair Javaid ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs)); 1342441aecdSOmair Javaid 1352441aecdSOmair Javaid // 16 is just a maximum value, query hardware for actual watchpoint count 1362441aecdSOmair Javaid m_max_hwp_supported = 16; 1372441aecdSOmair Javaid m_max_hbp_supported = 16; 1382441aecdSOmair Javaid m_refresh_hwdebug_info = true; 1393f57216cSOmair Javaid } 1403f57216cSOmair Javaid 141b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount() const { 1423f57216cSOmair Javaid return k_num_register_sets; 1433f57216cSOmair Javaid } 1443f57216cSOmair Javaid 145b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount() const { 1461f149204STamas Berghammer uint32_t count = 0; 1471f149204STamas Berghammer for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) 1481f149204STamas Berghammer count += g_reg_sets_arm[set_index].num_registers; 1491f149204STamas Berghammer return count; 1501f149204STamas Berghammer } 1511f149204STamas Berghammer 1523f57216cSOmair Javaid const RegisterSet * 153b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index) const { 1543f57216cSOmair Javaid if (set_index < k_num_register_sets) 1553f57216cSOmair Javaid return &g_reg_sets_arm[set_index]; 1563f57216cSOmair Javaid 1573f57216cSOmair Javaid return nullptr; 1583f57216cSOmair Javaid } 1593f57216cSOmair Javaid 160b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ReadRegister(const RegisterInfo *reg_info, 161b9c1b51eSKate Stone RegisterValue ®_value) { 1623f57216cSOmair Javaid Error error; 1633f57216cSOmair Javaid 164b9c1b51eSKate Stone if (!reg_info) { 1653f57216cSOmair Javaid error.SetErrorString("reg_info NULL"); 1663f57216cSOmair Javaid return error; 1673f57216cSOmair Javaid } 1683f57216cSOmair Javaid 1693f57216cSOmair Javaid const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 1703f57216cSOmair Javaid 171b9c1b51eSKate Stone if (IsFPR(reg)) { 172068f8a7eSTamas Berghammer error = ReadFPR(); 173068f8a7eSTamas Berghammer if (error.Fail()) 1743f57216cSOmair Javaid return error; 175b9c1b51eSKate Stone } else { 1763f57216cSOmair Javaid uint32_t full_reg = reg; 177b9c1b51eSKate Stone bool is_subreg = reg_info->invalidate_regs && 178b9c1b51eSKate Stone (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 1793f57216cSOmair Javaid 180b9c1b51eSKate Stone if (is_subreg) { 1813f57216cSOmair Javaid // Read the full aligned 64-bit register. 1823f57216cSOmair Javaid full_reg = reg_info->invalidate_regs[0]; 1833f57216cSOmair Javaid } 1843f57216cSOmair Javaid 1853f57216cSOmair Javaid error = ReadRegisterRaw(full_reg, reg_value); 1863f57216cSOmair Javaid 187b9c1b51eSKate Stone if (error.Success()) { 188b9c1b51eSKate Stone // If our read was not aligned (for ah,bh,ch,dh), shift our returned value 189b9c1b51eSKate Stone // one byte to the right. 1903f57216cSOmair Javaid if (is_subreg && (reg_info->byte_offset & 0x1)) 1913f57216cSOmair Javaid reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); 1923f57216cSOmair Javaid 193b9c1b51eSKate Stone // If our return byte size was greater than the return value reg size, 194b9c1b51eSKate Stone // then 1953f57216cSOmair Javaid // use the type specified by reg_info rather than the uint64_t default 1963f57216cSOmair Javaid if (reg_value.GetByteSize() > reg_info->byte_size) 1973f57216cSOmair Javaid reg_value.SetType(reg_info); 1983f57216cSOmair Javaid } 1993f57216cSOmair Javaid return error; 2003f57216cSOmair Javaid } 2013f57216cSOmair Javaid 2023f57216cSOmair Javaid // Get pointer to m_fpr variable and set the data from it. 203c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 204c40e7b17STamas Berghammer assert(fpr_offset < sizeof m_fpr); 205c40e7b17STamas Berghammer uint8_t *src = (uint8_t *)&m_fpr + fpr_offset; 206b9c1b51eSKate Stone switch (reg_info->byte_size) { 2073f57216cSOmair Javaid case 2: 2083f57216cSOmair Javaid reg_value.SetUInt16(*(uint16_t *)src); 2093f57216cSOmair Javaid break; 2103f57216cSOmair Javaid case 4: 2113f57216cSOmair Javaid reg_value.SetUInt32(*(uint32_t *)src); 2123f57216cSOmair Javaid break; 2133f57216cSOmair Javaid case 8: 2143f57216cSOmair Javaid reg_value.SetUInt64(*(uint64_t *)src); 2153f57216cSOmair Javaid break; 216b4e95a50STamas Berghammer case 16: 217b4e95a50STamas Berghammer reg_value.SetBytes(src, 16, GetByteOrder()); 218b4e95a50STamas Berghammer break; 2193f57216cSOmair Javaid default: 2203f57216cSOmair Javaid assert(false && "Unhandled data size."); 221b9c1b51eSKate Stone error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, 222b9c1b51eSKate Stone reg_info->byte_size); 2233f57216cSOmair Javaid break; 2243f57216cSOmair Javaid } 2253f57216cSOmair Javaid 2263f57216cSOmair Javaid return error; 2273f57216cSOmair Javaid } 2283f57216cSOmair Javaid 229b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::WriteRegister( 230b9c1b51eSKate Stone const RegisterInfo *reg_info, const RegisterValue ®_value) { 2313f57216cSOmair Javaid if (!reg_info) 2323f57216cSOmair Javaid return Error("reg_info NULL"); 2333f57216cSOmair Javaid 2343f57216cSOmair Javaid const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 2353f57216cSOmair Javaid if (reg_index == LLDB_INVALID_REGNUM) 236b9c1b51eSKate Stone return Error("no lldb regnum for %s", reg_info && reg_info->name 237b9c1b51eSKate Stone ? reg_info->name 238b9c1b51eSKate Stone : "<unknown register>"); 2393f57216cSOmair Javaid 2403f57216cSOmair Javaid if (IsGPR(reg_index)) 2413f57216cSOmair Javaid return WriteRegisterRaw(reg_index, reg_value); 2423f57216cSOmair Javaid 243b9c1b51eSKate Stone if (IsFPR(reg_index)) { 2443f57216cSOmair Javaid // Get pointer to m_fpr variable and set the data to it. 245c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 246c40e7b17STamas Berghammer assert(fpr_offset < sizeof m_fpr); 247c40e7b17STamas Berghammer uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset; 248b9c1b51eSKate Stone switch (reg_info->byte_size) { 2493f57216cSOmair Javaid case 2: 2503f57216cSOmair Javaid *(uint16_t *)dst = reg_value.GetAsUInt16(); 2513f57216cSOmair Javaid break; 2523f57216cSOmair Javaid case 4: 2533f57216cSOmair Javaid *(uint32_t *)dst = reg_value.GetAsUInt32(); 2543f57216cSOmair Javaid break; 2553f57216cSOmair Javaid case 8: 2563f57216cSOmair Javaid *(uint64_t *)dst = reg_value.GetAsUInt64(); 2573f57216cSOmair Javaid break; 2583f57216cSOmair Javaid default: 2593f57216cSOmair Javaid assert(false && "Unhandled data size."); 260b9c1b51eSKate Stone return Error("unhandled register data size %" PRIu32, 261b9c1b51eSKate Stone reg_info->byte_size); 2623f57216cSOmair Javaid } 2633f57216cSOmair Javaid 264068f8a7eSTamas Berghammer Error error = WriteFPR(); 265068f8a7eSTamas Berghammer if (error.Fail()) 266068f8a7eSTamas Berghammer return error; 2673f57216cSOmair Javaid 268665be50eSMehdi Amini return Error(); 2693f57216cSOmair Javaid } 2703f57216cSOmair Javaid 271b9c1b51eSKate Stone return Error("failed - register wasn't recognized to be a GPR or an FPR, " 272b9c1b51eSKate Stone "write strategy unknown"); 2733f57216cSOmair Javaid } 2743f57216cSOmair Javaid 275b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ReadAllRegisterValues( 276b9c1b51eSKate Stone lldb::DataBufferSP &data_sp) { 2773f57216cSOmair Javaid Error error; 2783f57216cSOmair Javaid 2793f57216cSOmair Javaid data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 2803f57216cSOmair Javaid if (!data_sp) 281b9c1b51eSKate Stone return Error("failed to allocate DataBufferHeap instance of size %" PRIu64, 282b9c1b51eSKate Stone (uint64_t)REG_CONTEXT_SIZE); 2833f57216cSOmair Javaid 284068f8a7eSTamas Berghammer error = ReadGPR(); 285068f8a7eSTamas Berghammer if (error.Fail()) 2863f57216cSOmair Javaid return error; 2873f57216cSOmair Javaid 288068f8a7eSTamas Berghammer error = ReadFPR(); 289068f8a7eSTamas Berghammer if (error.Fail()) 2903f57216cSOmair Javaid return error; 2913f57216cSOmair Javaid 2923f57216cSOmair Javaid uint8_t *dst = data_sp->GetBytes(); 293b9c1b51eSKate Stone if (dst == nullptr) { 294b9c1b51eSKate Stone error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 295b9c1b51eSKate Stone " returned a null pointer", 296b9c1b51eSKate Stone (uint64_t)REG_CONTEXT_SIZE); 2973f57216cSOmair Javaid return error; 2983f57216cSOmair Javaid } 2993f57216cSOmair Javaid 3003f57216cSOmair Javaid ::memcpy(dst, &m_gpr_arm, GetGPRSize()); 3013f57216cSOmair Javaid dst += GetGPRSize(); 3023f57216cSOmair Javaid ::memcpy(dst, &m_fpr, sizeof(m_fpr)); 3033f57216cSOmair Javaid 3043f57216cSOmair Javaid return error; 3053f57216cSOmair Javaid } 3063f57216cSOmair Javaid 307b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::WriteAllRegisterValues( 308b9c1b51eSKate Stone const lldb::DataBufferSP &data_sp) { 3093f57216cSOmair Javaid Error error; 3103f57216cSOmair Javaid 311b9c1b51eSKate Stone if (!data_sp) { 312b9c1b51eSKate Stone error.SetErrorStringWithFormat( 313b9c1b51eSKate Stone "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", 314b9c1b51eSKate Stone __FUNCTION__); 3153f57216cSOmair Javaid return error; 3163f57216cSOmair Javaid } 3173f57216cSOmair Javaid 318b9c1b51eSKate Stone if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 319b9c1b51eSKate Stone error.SetErrorStringWithFormat( 320b9c1b51eSKate Stone "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " 321b9c1b51eSKate Stone "data size, expected %" PRIu64 ", actual %" PRIu64, 322b9c1b51eSKate Stone __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize()); 3233f57216cSOmair Javaid return error; 3243f57216cSOmair Javaid } 3253f57216cSOmair Javaid 3263f57216cSOmair Javaid uint8_t *src = data_sp->GetBytes(); 327b9c1b51eSKate Stone if (src == nullptr) { 328b9c1b51eSKate Stone error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " 329b9c1b51eSKate Stone "DataBuffer::GetBytes() returned a null " 330b9c1b51eSKate Stone "pointer", 331b9c1b51eSKate Stone __FUNCTION__); 3323f57216cSOmair Javaid return error; 3333f57216cSOmair Javaid } 3343f57216cSOmair Javaid ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize()); 3353f57216cSOmair Javaid 336068f8a7eSTamas Berghammer error = WriteGPR(); 337068f8a7eSTamas Berghammer if (error.Fail()) 3383f57216cSOmair Javaid return error; 3393f57216cSOmair Javaid 3403f57216cSOmair Javaid src += GetRegisterInfoInterface().GetGPRSize(); 3413f57216cSOmair Javaid ::memcpy(&m_fpr, src, sizeof(m_fpr)); 3423f57216cSOmair Javaid 343068f8a7eSTamas Berghammer error = WriteFPR(); 3443f57216cSOmair Javaid if (error.Fail()) 3453f57216cSOmair Javaid return error; 3463f57216cSOmair Javaid 3473f57216cSOmair Javaid return error; 3483f57216cSOmair Javaid } 3493f57216cSOmair Javaid 350b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const { 3513f57216cSOmair Javaid return reg <= m_reg_info.last_gpr; // GPR's come first. 3523f57216cSOmair Javaid } 3533f57216cSOmair Javaid 354b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const { 3553f57216cSOmair Javaid return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 3563f57216cSOmair Javaid } 3573f57216cSOmair Javaid 358*d5ffbad2SOmair Javaid uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() { 359*d5ffbad2SOmair Javaid Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 360*d5ffbad2SOmair Javaid 361*d5ffbad2SOmair Javaid if (log) 362*d5ffbad2SOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 363*d5ffbad2SOmair Javaid 364*d5ffbad2SOmair Javaid Error error; 365*d5ffbad2SOmair Javaid 366*d5ffbad2SOmair Javaid // Read hardware breakpoint and watchpoint information. 367*d5ffbad2SOmair Javaid error = ReadHardwareDebugInfo(); 368*d5ffbad2SOmair Javaid 369*d5ffbad2SOmair Javaid if (error.Fail()) 370*d5ffbad2SOmair Javaid return 0; 371*d5ffbad2SOmair Javaid 372*d5ffbad2SOmair Javaid LLDB_LOG(log, "{0}", m_max_hbp_supported); 373*d5ffbad2SOmair Javaid return m_max_hbp_supported; 374*d5ffbad2SOmair Javaid } 375*d5ffbad2SOmair Javaid 3762441aecdSOmair Javaid uint32_t 377b9c1b51eSKate Stone NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr, 378b9c1b51eSKate Stone size_t size) { 379*d5ffbad2SOmair Javaid Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 380ea1b6b17SPavel Labath LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size); 3812441aecdSOmair Javaid 3822441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 383ea1b6b17SPavel Labath Error error = ReadHardwareDebugInfo(); 3842441aecdSOmair Javaid 3852441aecdSOmair Javaid if (error.Fail()) 3862441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 3872441aecdSOmair Javaid 3882441aecdSOmair Javaid uint32_t control_value = 0, bp_index = 0; 3892441aecdSOmair Javaid 390*d5ffbad2SOmair Javaid // Setup address and control values. 391*d5ffbad2SOmair Javaid // Use size to get a hint of arm vs thumb modes. 392*d5ffbad2SOmair Javaid switch (size) { 393*d5ffbad2SOmair Javaid case 2: 394*d5ffbad2SOmair Javaid control_value = (0x3 << 5) | 7; 395*d5ffbad2SOmair Javaid addr &= ~1; 396*d5ffbad2SOmair Javaid break; 397*d5ffbad2SOmair Javaid case 4: 398*d5ffbad2SOmair Javaid control_value = (0xfu << 5) | 7; 399*d5ffbad2SOmair Javaid addr &= ~3; 400*d5ffbad2SOmair Javaid break; 401*d5ffbad2SOmair Javaid default: 4022441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 403*d5ffbad2SOmair Javaid } 4042441aecdSOmair Javaid 405*d5ffbad2SOmair Javaid // Iterate over stored breakpoints and find a free bp_index 4062441aecdSOmair Javaid bp_index = LLDB_INVALID_INDEX32; 407b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 408b9c1b51eSKate Stone if ((m_hbr_regs[i].control & 1) == 0) { 4092441aecdSOmair Javaid bp_index = i; // Mark last free slot 410*d5ffbad2SOmair Javaid } else if (m_hbr_regs[i].address == addr) { 411*d5ffbad2SOmair Javaid return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints. 4122441aecdSOmair Javaid } 4132441aecdSOmair Javaid } 4142441aecdSOmair Javaid 4152441aecdSOmair Javaid if (bp_index == LLDB_INVALID_INDEX32) 4162441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 4172441aecdSOmair Javaid 418*d5ffbad2SOmair Javaid // Update breakpoint in local cache 419*d5ffbad2SOmair Javaid m_hbr_regs[bp_index].real_addr = addr; 4202441aecdSOmair Javaid m_hbr_regs[bp_index].address = addr; 4212441aecdSOmair Javaid m_hbr_regs[bp_index].control = control_value; 4222441aecdSOmair Javaid 4232441aecdSOmair Javaid // PTRACE call to set corresponding hardware breakpoint register. 4242441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index); 4252441aecdSOmair Javaid 426b9c1b51eSKate Stone if (error.Fail()) { 427d5510d1eSOmair Javaid m_hbr_regs[bp_index].address = 0; 428d5510d1eSOmair Javaid m_hbr_regs[bp_index].control &= ~1; 429d5510d1eSOmair Javaid 4302441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 4312441aecdSOmair Javaid } 4322441aecdSOmair Javaid 4332441aecdSOmair Javaid return bp_index; 4342441aecdSOmair Javaid } 4352441aecdSOmair Javaid 436b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) { 437*d5ffbad2SOmair Javaid Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 438ea1b6b17SPavel Labath LLDB_LOG(log, "hw_idx: {0}", hw_idx); 4392441aecdSOmair Javaid 4402441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 441*d5ffbad2SOmair Javaid Error error = ReadHardwareDebugInfo(); 4422441aecdSOmair Javaid 4432441aecdSOmair Javaid if (error.Fail()) 4444aa984c1SOmair Javaid return false; 4452441aecdSOmair Javaid 4462441aecdSOmair Javaid if (hw_idx >= m_max_hbp_supported) 4472441aecdSOmair Javaid return false; 4482441aecdSOmair Javaid 449d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 450d5510d1eSOmair Javaid lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; 451d5510d1eSOmair Javaid uint32_t tempControl = m_hbr_regs[hw_idx].control; 452d5510d1eSOmair Javaid 4532441aecdSOmair Javaid m_hbr_regs[hw_idx].control &= ~1; 4542441aecdSOmair Javaid m_hbr_regs[hw_idx].address = 0; 4552441aecdSOmair Javaid 4562441aecdSOmair Javaid // PTRACE call to clear corresponding hardware breakpoint register. 457*d5ffbad2SOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx); 4582441aecdSOmair Javaid 459b9c1b51eSKate Stone if (error.Fail()) { 460d5510d1eSOmair Javaid m_hbr_regs[hw_idx].control = tempControl; 461d5510d1eSOmair Javaid m_hbr_regs[hw_idx].address = tempAddr; 462d5510d1eSOmair Javaid 4634aa984c1SOmair Javaid return false; 464d5510d1eSOmair Javaid } 4652441aecdSOmair Javaid 4662441aecdSOmair Javaid return true; 4672441aecdSOmair Javaid } 4682441aecdSOmair Javaid 469*d5ffbad2SOmair Javaid Error NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex( 470*d5ffbad2SOmair Javaid uint32_t &bp_index, lldb::addr_t trap_addr) { 471*d5ffbad2SOmair Javaid Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 472*d5ffbad2SOmair Javaid 473*d5ffbad2SOmair Javaid if (log) 474*d5ffbad2SOmair Javaid log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 475*d5ffbad2SOmair Javaid 476*d5ffbad2SOmair Javaid lldb::addr_t break_addr; 477*d5ffbad2SOmair Javaid 478*d5ffbad2SOmair Javaid for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) { 479*d5ffbad2SOmair Javaid break_addr = m_hbr_regs[bp_index].address; 480*d5ffbad2SOmair Javaid 481*d5ffbad2SOmair Javaid if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) { 482*d5ffbad2SOmair Javaid m_hbr_regs[bp_index].hit_addr = trap_addr; 483*d5ffbad2SOmair Javaid return Error(); 484*d5ffbad2SOmair Javaid } 485*d5ffbad2SOmair Javaid } 486*d5ffbad2SOmair Javaid 487*d5ffbad2SOmair Javaid bp_index = LLDB_INVALID_INDEX32; 488*d5ffbad2SOmair Javaid return Error(); 489*d5ffbad2SOmair Javaid } 490*d5ffbad2SOmair Javaid 491*d5ffbad2SOmair Javaid Error NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() { 492*d5ffbad2SOmair Javaid Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 493*d5ffbad2SOmair Javaid 494*d5ffbad2SOmair Javaid if (log) 495*d5ffbad2SOmair Javaid log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 496*d5ffbad2SOmair Javaid 497*d5ffbad2SOmair Javaid Error error; 498*d5ffbad2SOmair Javaid 499*d5ffbad2SOmair Javaid // Read hardware breakpoint and watchpoint information. 500*d5ffbad2SOmair Javaid error = ReadHardwareDebugInfo(); 501*d5ffbad2SOmair Javaid 502*d5ffbad2SOmair Javaid if (error.Fail()) 503*d5ffbad2SOmair Javaid return error; 504*d5ffbad2SOmair Javaid 505*d5ffbad2SOmair Javaid lldb::addr_t tempAddr = 0; 506*d5ffbad2SOmair Javaid uint32_t tempControl = 0; 507*d5ffbad2SOmair Javaid 508*d5ffbad2SOmair Javaid for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 509*d5ffbad2SOmair Javaid if (m_hbr_regs[i].control & 0x01) { 510*d5ffbad2SOmair Javaid // Create a backup we can revert to in case of failure. 511*d5ffbad2SOmair Javaid tempAddr = m_hbr_regs[i].address; 512*d5ffbad2SOmair Javaid tempControl = m_hbr_regs[i].control; 513*d5ffbad2SOmair Javaid 514*d5ffbad2SOmair Javaid // Clear breakpoints in local cache 515*d5ffbad2SOmair Javaid m_hbr_regs[i].control &= ~1; 516*d5ffbad2SOmair Javaid m_hbr_regs[i].address = 0; 517*d5ffbad2SOmair Javaid 518*d5ffbad2SOmair Javaid // Ptrace call to update hardware debug registers 519*d5ffbad2SOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK, i); 520*d5ffbad2SOmair Javaid 521*d5ffbad2SOmair Javaid if (error.Fail()) { 522*d5ffbad2SOmair Javaid m_hbr_regs[i].control = tempControl; 523*d5ffbad2SOmair Javaid m_hbr_regs[i].address = tempAddr; 524*d5ffbad2SOmair Javaid 525*d5ffbad2SOmair Javaid return error; 526*d5ffbad2SOmair Javaid } 527*d5ffbad2SOmair Javaid } 528*d5ffbad2SOmair Javaid } 529*d5ffbad2SOmair Javaid 530*d5ffbad2SOmair Javaid return Error(); 5312441aecdSOmair Javaid } 5322441aecdSOmair Javaid 533b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() { 534ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 5352441aecdSOmair Javaid 5362441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 537ea1b6b17SPavel Labath Error error = ReadHardwareDebugInfo(); 5382441aecdSOmair Javaid 5392441aecdSOmair Javaid if (error.Fail()) 54062661473SOmair Javaid return 0; 5412441aecdSOmair Javaid 542ea1b6b17SPavel Labath LLDB_LOG(log, "{0}", m_max_hwp_supported); 5432441aecdSOmair Javaid return m_max_hwp_supported; 5442441aecdSOmair Javaid } 5452441aecdSOmair Javaid 546b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint( 547b9c1b51eSKate Stone lldb::addr_t addr, size_t size, uint32_t watch_flags) { 548ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 549ea1b6b17SPavel Labath LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, 550ea1b6b17SPavel Labath watch_flags); 5512441aecdSOmair Javaid 5522441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 553ea1b6b17SPavel Labath Error error = ReadHardwareDebugInfo(); 5542441aecdSOmair Javaid 5552441aecdSOmair Javaid if (error.Fail()) 5562441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5572441aecdSOmair Javaid 5582441aecdSOmair Javaid uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0; 559c6dc90efSOmair Javaid lldb::addr_t real_addr = addr; 5602441aecdSOmair Javaid 5612441aecdSOmair Javaid // Check if we are setting watchpoint other than read/write/access 5622441aecdSOmair Javaid // Also update watchpoint flag to match Arm write-read bit configuration. 563b9c1b51eSKate Stone switch (watch_flags) { 5642441aecdSOmair Javaid case 1: 5652441aecdSOmair Javaid watch_flags = 2; 5662441aecdSOmair Javaid break; 5672441aecdSOmair Javaid case 2: 5682441aecdSOmair Javaid watch_flags = 1; 5692441aecdSOmair Javaid break; 5702441aecdSOmair Javaid case 3: 5712441aecdSOmair Javaid break; 5722441aecdSOmair Javaid default: 5732441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5742441aecdSOmair Javaid } 5752441aecdSOmair Javaid 5762441aecdSOmair Javaid // Can't watch zero bytes 5772441aecdSOmair Javaid // Can't watch more than 4 bytes per WVR/WCR pair 5782441aecdSOmair Javaid 5792441aecdSOmair Javaid if (size == 0 || size > 4) 5802441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5812441aecdSOmair Javaid 582c6dc90efSOmair Javaid // Check 4-byte alignment for hardware watchpoint target address. 583c6dc90efSOmair Javaid // Below is a hack to recalculate address and size in order to 584c6dc90efSOmair Javaid // make sure we can watch non 4-byte alligned addresses as well. 585b9c1b51eSKate Stone if (addr & 0x03) { 586c6dc90efSOmair Javaid uint8_t watch_mask = (addr & 0x03) + size; 587c6dc90efSOmair Javaid 588c6dc90efSOmair Javaid if (watch_mask > 0x04) 589c6dc90efSOmair Javaid return LLDB_INVALID_INDEX32; 590c6dc90efSOmair Javaid else if (watch_mask <= 0x02) 591c6dc90efSOmair Javaid size = 2; 592c6dc90efSOmair Javaid else if (watch_mask <= 0x04) 593c6dc90efSOmair Javaid size = 4; 594c6dc90efSOmair Javaid 595c6dc90efSOmair Javaid addr = addr & (~0x03); 596c6dc90efSOmair Javaid } 597c6dc90efSOmair Javaid 5982441aecdSOmair Javaid // We can only watch up to four bytes that follow a 4 byte aligned address 5992441aecdSOmair Javaid // per watchpoint register pair, so make sure we can properly encode this. 6002441aecdSOmair Javaid addr_word_offset = addr % 4; 6012441aecdSOmair Javaid byte_mask = ((1u << size) - 1u) << addr_word_offset; 6022441aecdSOmair Javaid 6032441aecdSOmair Javaid // Check if we need multiple watchpoint register 6042441aecdSOmair Javaid if (byte_mask > 0xfu) 6052441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 6062441aecdSOmair Javaid 6072441aecdSOmair Javaid // Setup control value 6082441aecdSOmair Javaid // Make the byte_mask into a valid Byte Address Select mask 6092441aecdSOmair Javaid control_value = byte_mask << 5; 6102441aecdSOmair Javaid 6112441aecdSOmair Javaid // Turn on appropriate watchpoint flags read or write 6122441aecdSOmair Javaid control_value |= (watch_flags << 3); 6132441aecdSOmair Javaid 6142441aecdSOmair Javaid // Enable this watchpoint and make it stop in privileged or user mode; 6152441aecdSOmair Javaid control_value |= 7; 6162441aecdSOmair Javaid 6172441aecdSOmair Javaid // Make sure bits 1:0 are clear in our address 6182441aecdSOmair Javaid addr &= ~((lldb::addr_t)3); 6192441aecdSOmair Javaid 62005ac4c44SOmair Javaid // Iterate over stored watchpoints and find a free wp_index 6212441aecdSOmair Javaid wp_index = LLDB_INVALID_INDEX32; 622b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 623b9c1b51eSKate Stone if ((m_hwp_regs[i].control & 1) == 0) { 6242441aecdSOmair Javaid wp_index = i; // Mark last free slot 62505ac4c44SOmair Javaid } else if (m_hwp_regs[i].address == addr) { 62605ac4c44SOmair Javaid return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. 6272441aecdSOmair Javaid } 6282441aecdSOmair Javaid } 6292441aecdSOmair Javaid 6302441aecdSOmair Javaid if (wp_index == LLDB_INVALID_INDEX32) 6312441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 6322441aecdSOmair Javaid 6332441aecdSOmair Javaid // Update watchpoint in local cache 634c6dc90efSOmair Javaid m_hwp_regs[wp_index].real_addr = real_addr; 6352441aecdSOmair Javaid m_hwp_regs[wp_index].address = addr; 6362441aecdSOmair Javaid m_hwp_regs[wp_index].control = control_value; 6372441aecdSOmair Javaid 6382441aecdSOmair Javaid // PTRACE call to set corresponding watchpoint register. 6392441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); 6402441aecdSOmair Javaid 641b9c1b51eSKate Stone if (error.Fail()) { 642d5510d1eSOmair Javaid m_hwp_regs[wp_index].address = 0; 643d5510d1eSOmair Javaid m_hwp_regs[wp_index].control &= ~1; 644d5510d1eSOmair Javaid 6452441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 6462441aecdSOmair Javaid } 6472441aecdSOmair Javaid 6482441aecdSOmair Javaid return wp_index; 6492441aecdSOmair Javaid } 6502441aecdSOmair Javaid 651b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint( 652b9c1b51eSKate Stone uint32_t wp_index) { 653ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 654ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}", wp_index); 6552441aecdSOmair Javaid 6562441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 657ea1b6b17SPavel Labath Error error = ReadHardwareDebugInfo(); 6582441aecdSOmair Javaid 6592441aecdSOmair Javaid if (error.Fail()) 6604aa984c1SOmair Javaid return false; 6612441aecdSOmair Javaid 6622441aecdSOmair Javaid if (wp_index >= m_max_hwp_supported) 6632441aecdSOmair Javaid return false; 6642441aecdSOmair Javaid 665d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 666d5510d1eSOmair Javaid lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 667d5510d1eSOmair Javaid uint32_t tempControl = m_hwp_regs[wp_index].control; 668d5510d1eSOmair Javaid 6692441aecdSOmair Javaid // Update watchpoint in local cache 6702441aecdSOmair Javaid m_hwp_regs[wp_index].control &= ~1; 6712441aecdSOmair Javaid m_hwp_regs[wp_index].address = 0; 6722441aecdSOmair Javaid 6732441aecdSOmair Javaid // Ptrace call to update hardware debug registers 6742441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); 6752441aecdSOmair Javaid 676b9c1b51eSKate Stone if (error.Fail()) { 677d5510d1eSOmair Javaid m_hwp_regs[wp_index].control = tempControl; 678d5510d1eSOmair Javaid m_hwp_regs[wp_index].address = tempAddr; 679d5510d1eSOmair Javaid 6802441aecdSOmair Javaid return false; 681d5510d1eSOmair Javaid } 6822441aecdSOmair Javaid 6832441aecdSOmair Javaid return true; 6842441aecdSOmair Javaid } 6852441aecdSOmair Javaid 686b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() { 6872441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 688ea1b6b17SPavel Labath Error error = ReadHardwareDebugInfo(); 6892441aecdSOmair Javaid 6902441aecdSOmair Javaid if (error.Fail()) 6912441aecdSOmair Javaid return error; 6922441aecdSOmair Javaid 693d5510d1eSOmair Javaid lldb::addr_t tempAddr = 0; 69405ac4c44SOmair Javaid uint32_t tempControl = 0; 695d5510d1eSOmair Javaid 696b9c1b51eSKate Stone for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 697b9c1b51eSKate Stone if (m_hwp_regs[i].control & 0x01) { 698d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 699d5510d1eSOmair Javaid tempAddr = m_hwp_regs[i].address; 700d5510d1eSOmair Javaid tempControl = m_hwp_regs[i].control; 701d5510d1eSOmair Javaid 7022441aecdSOmair Javaid // Clear watchpoints in local cache 7032441aecdSOmair Javaid m_hwp_regs[i].control &= ~1; 7042441aecdSOmair Javaid m_hwp_regs[i].address = 0; 7052441aecdSOmair Javaid 7062441aecdSOmair Javaid // Ptrace call to update hardware debug registers 7072441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, i); 7082441aecdSOmair Javaid 709b9c1b51eSKate Stone if (error.Fail()) { 710d5510d1eSOmair Javaid m_hwp_regs[i].control = tempControl; 711d5510d1eSOmair Javaid m_hwp_regs[i].address = tempAddr; 712d5510d1eSOmair Javaid 7132441aecdSOmair Javaid return error; 7142441aecdSOmair Javaid } 7152441aecdSOmair Javaid } 716d5510d1eSOmair Javaid } 7172441aecdSOmair Javaid 718665be50eSMehdi Amini return Error(); 7192441aecdSOmair Javaid } 7202441aecdSOmair Javaid 721b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) { 722ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 723ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}", wp_index); 7242441aecdSOmair Javaid 725b9c1b51eSKate Stone switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) { 7262441aecdSOmair Javaid case 0x01: 7272441aecdSOmair Javaid return 1; 7282441aecdSOmair Javaid case 0x03: 7292441aecdSOmair Javaid return 2; 7302441aecdSOmair Javaid case 0x07: 7312441aecdSOmair Javaid return 3; 7322441aecdSOmair Javaid case 0x0f: 7332441aecdSOmair Javaid return 4; 7342441aecdSOmair Javaid default: 7352441aecdSOmair Javaid return 0; 7362441aecdSOmair Javaid } 7372441aecdSOmair Javaid } 738b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) { 739ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 740ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}", wp_index); 7412441aecdSOmair Javaid 7422441aecdSOmair Javaid if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 7432441aecdSOmair Javaid return true; 7442441aecdSOmair Javaid else 7452441aecdSOmair Javaid return false; 7462441aecdSOmair Javaid } 7472441aecdSOmair Javaid 748b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::GetWatchpointHitIndex( 749b9c1b51eSKate Stone uint32_t &wp_index, lldb::addr_t trap_addr) { 750ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 751ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); 7522441aecdSOmair Javaid 7532441aecdSOmair Javaid uint32_t watch_size; 7542441aecdSOmair Javaid lldb::addr_t watch_addr; 7552441aecdSOmair Javaid 756b9c1b51eSKate Stone for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { 7572441aecdSOmair Javaid watch_size = GetWatchpointSize(wp_index); 7582441aecdSOmair Javaid watch_addr = m_hwp_regs[wp_index].address; 7592441aecdSOmair Javaid 76005ac4c44SOmair Javaid if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && 76105ac4c44SOmair Javaid trap_addr < watch_addr + watch_size) { 762c6dc90efSOmair Javaid m_hwp_regs[wp_index].hit_addr = trap_addr; 763665be50eSMehdi Amini return Error(); 7642441aecdSOmair Javaid } 7652441aecdSOmair Javaid } 7662441aecdSOmair Javaid 7672441aecdSOmair Javaid wp_index = LLDB_INVALID_INDEX32; 768665be50eSMehdi Amini return Error(); 7692441aecdSOmair Javaid } 7702441aecdSOmair Javaid 7712441aecdSOmair Javaid lldb::addr_t 772b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) { 773ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 774ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}", wp_index); 7752441aecdSOmair Javaid 7762441aecdSOmair Javaid if (wp_index >= m_max_hwp_supported) 7772441aecdSOmair Javaid return LLDB_INVALID_ADDRESS; 7782441aecdSOmair Javaid 7792441aecdSOmair Javaid if (WatchpointIsEnabled(wp_index)) 780c6dc90efSOmair Javaid return m_hwp_regs[wp_index].real_addr; 781c6dc90efSOmair Javaid else 782c6dc90efSOmair Javaid return LLDB_INVALID_ADDRESS; 783c6dc90efSOmair Javaid } 784c6dc90efSOmair Javaid 785c6dc90efSOmair Javaid lldb::addr_t 786b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) { 787ea1b6b17SPavel Labath Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 788ea1b6b17SPavel Labath LLDB_LOG(log, "wp_index: {0}", wp_index); 789c6dc90efSOmair Javaid 790c6dc90efSOmair Javaid if (wp_index >= m_max_hwp_supported) 791c6dc90efSOmair Javaid return LLDB_INVALID_ADDRESS; 792c6dc90efSOmair Javaid 793c6dc90efSOmair Javaid if (WatchpointIsEnabled(wp_index)) 794c6dc90efSOmair Javaid return m_hwp_regs[wp_index].hit_addr; 7952441aecdSOmair Javaid else 7962441aecdSOmair Javaid return LLDB_INVALID_ADDRESS; 7972441aecdSOmair Javaid } 7982441aecdSOmair Javaid 799b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() { 8002441aecdSOmair Javaid Error error; 8012441aecdSOmair Javaid 802b9c1b51eSKate Stone if (!m_refresh_hwdebug_info) { 803665be50eSMehdi Amini return Error(); 8042441aecdSOmair Javaid } 8052441aecdSOmair Javaid 8062441aecdSOmair Javaid unsigned int cap_val; 8072441aecdSOmair Javaid 808b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), 809b9c1b51eSKate Stone nullptr, &cap_val, 810b9c1b51eSKate Stone sizeof(unsigned int)); 8112441aecdSOmair Javaid 8122441aecdSOmair Javaid if (error.Fail()) 8132441aecdSOmair Javaid return error; 8142441aecdSOmair Javaid 8152441aecdSOmair Javaid m_max_hwp_supported = (cap_val >> 8) & 0xff; 8162441aecdSOmair Javaid m_max_hbp_supported = cap_val & 0xff; 8172441aecdSOmair Javaid m_refresh_hwdebug_info = false; 8182441aecdSOmair Javaid 8192441aecdSOmair Javaid return error; 8202441aecdSOmair Javaid } 8212441aecdSOmair Javaid 822b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, 823b9c1b51eSKate Stone int hwb_index) { 8242441aecdSOmair Javaid Error error; 8252441aecdSOmair Javaid 8262441aecdSOmair Javaid lldb::addr_t *addr_buf; 8272441aecdSOmair Javaid uint32_t *ctrl_buf; 8282441aecdSOmair Javaid 829b9c1b51eSKate Stone if (hwbType == eDREGTypeWATCH) { 8302441aecdSOmair Javaid addr_buf = &m_hwp_regs[hwb_index].address; 8312441aecdSOmair Javaid ctrl_buf = &m_hwp_regs[hwb_index].control; 8322441aecdSOmair Javaid 833b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 834b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 835b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf, 836b9c1b51eSKate Stone sizeof(unsigned int)); 8372441aecdSOmair Javaid 8382441aecdSOmair Javaid if (error.Fail()) 8392441aecdSOmair Javaid return error; 8402441aecdSOmair Javaid 841b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 842b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 843b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf, 844b9c1b51eSKate Stone sizeof(unsigned int)); 845b9c1b51eSKate Stone } else { 846*d5ffbad2SOmair Javaid addr_buf = &m_hbr_regs[hwb_index].address; 847*d5ffbad2SOmair Javaid ctrl_buf = &m_hbr_regs[hwb_index].control; 8482441aecdSOmair Javaid 849b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 850b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 851b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf, 852b9c1b51eSKate Stone sizeof(unsigned int)); 8532441aecdSOmair Javaid 8542441aecdSOmair Javaid if (error.Fail()) 8552441aecdSOmair Javaid return error; 8562441aecdSOmair Javaid 857b9c1b51eSKate Stone error = NativeProcessLinux::PtraceWrapper( 858b9c1b51eSKate Stone PTRACE_SETHBPREGS, m_thread.GetID(), 859b9c1b51eSKate Stone (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf, 860b9c1b51eSKate Stone sizeof(unsigned int)); 8612441aecdSOmair Javaid } 8622441aecdSOmair Javaid 8632441aecdSOmair Javaid return error; 8642441aecdSOmair Javaid } 865c40e7b17STamas Berghammer 866b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset( 867b9c1b51eSKate Stone const RegisterInfo *reg_info) const { 868b9c1b51eSKate Stone return reg_info->byte_offset - 869b9c1b51eSKate Stone GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; 870c40e7b17STamas Berghammer } 871c40e7b17STamas Berghammer 872b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoReadRegisterValue( 873b9c1b51eSKate Stone uint32_t offset, const char *reg_name, uint32_t size, 874b9c1b51eSKate Stone RegisterValue &value) { 875b9c1b51eSKate Stone // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android 876b9c1b51eSKate Stone // devices (always return 877b9c1b51eSKate Stone // "Bad address"). To avoid using PTRACE_PEEKUSER we read out the full GPR 878b9c1b51eSKate Stone // register set instead. 879b9c1b51eSKate Stone // This approach is about 4 times slower but the performance overhead is 880b9c1b51eSKate Stone // negligible in 881e85e6021STamas Berghammer // comparision to processing time in lldb-server. 882e85e6021STamas Berghammer assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); 883e85e6021STamas Berghammer if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) 884e85e6021STamas Berghammer return Error("Register isn't fit into the size of the GPR area"); 885e85e6021STamas Berghammer 886e85e6021STamas Berghammer Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm)); 887e85e6021STamas Berghammer if (error.Fail()) 888e85e6021STamas Berghammer return error; 889e85e6021STamas Berghammer 890e85e6021STamas Berghammer value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]); 891665be50eSMehdi Amini return Error(); 892e85e6021STamas Berghammer } 893e85e6021STamas Berghammer 894b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoWriteRegisterValue( 895b9c1b51eSKate Stone uint32_t offset, const char *reg_name, const RegisterValue &value) { 896b9c1b51eSKate Stone // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android 897b9c1b51eSKate Stone // devices (always return 898b9c1b51eSKate Stone // "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR 899b9c1b51eSKate Stone // register set, modify 900b9c1b51eSKate Stone // the requested register and write it back. This approach is about 4 times 901b9c1b51eSKate Stone // slower but the 902b9c1b51eSKate Stone // performance overhead is negligible in comparision to processing time in 903b9c1b51eSKate Stone // lldb-server. 904ce26b7a6STamas Berghammer assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); 905ce26b7a6STamas Berghammer if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) 906ce26b7a6STamas Berghammer return Error("Register isn't fit into the size of the GPR area"); 907ce26b7a6STamas Berghammer 908ce26b7a6STamas Berghammer Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm)); 909ce26b7a6STamas Berghammer if (error.Fail()) 910ce26b7a6STamas Berghammer return error; 911ce26b7a6STamas Berghammer 912a7d7f7cfSOmair Javaid uint32_t reg_value = value.GetAsUInt32(); 913a7d7f7cfSOmair Javaid // As precaution for an undefined behavior encountered while setting PC we 914a7d7f7cfSOmair Javaid // will clear thumb bit of new PC if we are already in thumb mode; that is 915a7d7f7cfSOmair Javaid // CPSR thumb mode bit is set. 916b9c1b51eSKate Stone if (offset / sizeof(uint32_t) == gpr_pc_arm) { 917a7d7f7cfSOmair Javaid // Check if we are already in thumb mode and 918a7d7f7cfSOmair Javaid // thumb bit of current PC is read out to be zero and 919a7d7f7cfSOmair Javaid // thumb bit of next PC is read out to be one. 920b9c1b51eSKate Stone if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) && 921b9c1b51eSKate Stone (value.GetAsUInt32() & 0x01)) { 922a7d7f7cfSOmair Javaid reg_value &= (~1ull); 923a7d7f7cfSOmair Javaid } 924a7d7f7cfSOmair Javaid } 925a7d7f7cfSOmair Javaid 926a7d7f7cfSOmair Javaid m_gpr_arm[offset / sizeof(uint32_t)] = reg_value; 927ce26b7a6STamas Berghammer return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm)); 928ce26b7a6STamas Berghammer } 929ce26b7a6STamas Berghammer 930b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoReadGPR(void *buf, size_t buf_size) { 931e85e6021STamas Berghammer #ifdef __arm__ 932e85e6021STamas Berghammer return NativeRegisterContextLinux::DoReadGPR(buf, buf_size); 933e85e6021STamas Berghammer #else // __aarch64__ 934e85e6021STamas Berghammer struct iovec ioVec; 935e85e6021STamas Berghammer ioVec.iov_base = buf; 936e85e6021STamas Berghammer ioVec.iov_len = buf_size; 937e85e6021STamas Berghammer 938e85e6021STamas Berghammer return ReadRegisterSet(&ioVec, buf_size, NT_PRSTATUS); 939e85e6021STamas Berghammer #endif // __arm__ 940e85e6021STamas Berghammer } 941e85e6021STamas Berghammer 942b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoWriteGPR(void *buf, size_t buf_size) { 943e85e6021STamas Berghammer #ifdef __arm__ 944e85e6021STamas Berghammer return NativeRegisterContextLinux::DoWriteGPR(buf, buf_size); 945e85e6021STamas Berghammer #else // __aarch64__ 946e85e6021STamas Berghammer struct iovec ioVec; 947e85e6021STamas Berghammer ioVec.iov_base = buf; 948e85e6021STamas Berghammer ioVec.iov_len = buf_size; 949e85e6021STamas Berghammer 950e85e6021STamas Berghammer return WriteRegisterSet(&ioVec, buf_size, NT_PRSTATUS); 951e85e6021STamas Berghammer #endif // __arm__ 952e85e6021STamas Berghammer } 953e85e6021STamas Berghammer 954b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size) { 955e85e6021STamas Berghammer #ifdef __arm__ 956b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(), 957b9c1b51eSKate Stone nullptr, buf, buf_size); 958e85e6021STamas Berghammer #else // __aarch64__ 959e85e6021STamas Berghammer struct iovec ioVec; 960e85e6021STamas Berghammer ioVec.iov_base = buf; 961e85e6021STamas Berghammer ioVec.iov_len = buf_size; 962e85e6021STamas Berghammer 963e85e6021STamas Berghammer return ReadRegisterSet(&ioVec, buf_size, NT_ARM_VFP); 964e85e6021STamas Berghammer #endif // __arm__ 965ce26b7a6STamas Berghammer } 966ce26b7a6STamas Berghammer 967b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size) { 968e85e6021STamas Berghammer #ifdef __arm__ 969b9c1b51eSKate Stone return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(), 970b9c1b51eSKate Stone nullptr, buf, buf_size); 971e85e6021STamas Berghammer #else // __aarch64__ 972e85e6021STamas Berghammer struct iovec ioVec; 973e85e6021STamas Berghammer ioVec.iov_base = buf; 974e85e6021STamas Berghammer ioVec.iov_len = buf_size; 975e85e6021STamas Berghammer 976e85e6021STamas Berghammer return WriteRegisterSet(&ioVec, buf_size, NT_ARM_VFP); 977e85e6021STamas Berghammer #endif // __arm__ 978ce26b7a6STamas Berghammer } 979ce26b7a6STamas Berghammer 980e85e6021STamas Berghammer #endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 981