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. 473f57216cSOmair Javaid static const uint32_t g_gpr_regnums_arm[] = 483f57216cSOmair Javaid { 493f57216cSOmair Javaid gpr_r0_arm, 503f57216cSOmair Javaid gpr_r1_arm, 513f57216cSOmair Javaid gpr_r2_arm, 523f57216cSOmair Javaid gpr_r3_arm, 533f57216cSOmair Javaid gpr_r4_arm, 543f57216cSOmair Javaid gpr_r5_arm, 553f57216cSOmair Javaid gpr_r6_arm, 563f57216cSOmair Javaid gpr_r7_arm, 573f57216cSOmair Javaid gpr_r8_arm, 583f57216cSOmair Javaid gpr_r9_arm, 593f57216cSOmair Javaid gpr_r10_arm, 603f57216cSOmair Javaid gpr_r11_arm, 613f57216cSOmair Javaid gpr_r12_arm, 623f57216cSOmair Javaid gpr_sp_arm, 633f57216cSOmair Javaid gpr_lr_arm, 643f57216cSOmair Javaid gpr_pc_arm, 653f57216cSOmair Javaid gpr_cpsr_arm, 663f57216cSOmair Javaid LLDB_INVALID_REGNUM // register sets need to end with this flag 673f57216cSOmair Javaid }; 683f57216cSOmair Javaid static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == k_num_gpr_registers_arm, \ 693f57216cSOmair Javaid "g_gpr_regnums_arm has wrong number of register infos"); 703f57216cSOmair Javaid 713f57216cSOmair Javaid // arm floating point registers. 723f57216cSOmair Javaid static const uint32_t g_fpu_regnums_arm[] = 733f57216cSOmair Javaid { 743f57216cSOmair Javaid fpu_s0_arm, 753f57216cSOmair Javaid fpu_s1_arm, 763f57216cSOmair Javaid fpu_s2_arm, 773f57216cSOmair Javaid fpu_s3_arm, 783f57216cSOmair Javaid fpu_s4_arm, 793f57216cSOmair Javaid fpu_s5_arm, 803f57216cSOmair Javaid fpu_s6_arm, 813f57216cSOmair Javaid fpu_s7_arm, 823f57216cSOmair Javaid fpu_s8_arm, 833f57216cSOmair Javaid fpu_s9_arm, 843f57216cSOmair Javaid fpu_s10_arm, 853f57216cSOmair Javaid fpu_s11_arm, 863f57216cSOmair Javaid fpu_s12_arm, 873f57216cSOmair Javaid fpu_s13_arm, 883f57216cSOmair Javaid fpu_s14_arm, 893f57216cSOmair Javaid fpu_s15_arm, 903f57216cSOmair Javaid fpu_s16_arm, 913f57216cSOmair Javaid fpu_s17_arm, 923f57216cSOmair Javaid fpu_s18_arm, 933f57216cSOmair Javaid fpu_s19_arm, 943f57216cSOmair Javaid fpu_s20_arm, 953f57216cSOmair Javaid fpu_s21_arm, 963f57216cSOmair Javaid fpu_s22_arm, 973f57216cSOmair Javaid fpu_s23_arm, 983f57216cSOmair Javaid fpu_s24_arm, 993f57216cSOmair Javaid fpu_s25_arm, 1003f57216cSOmair Javaid fpu_s26_arm, 1013f57216cSOmair Javaid fpu_s27_arm, 1023f57216cSOmair Javaid fpu_s28_arm, 1033f57216cSOmair Javaid fpu_s29_arm, 1043f57216cSOmair Javaid fpu_s30_arm, 1053f57216cSOmair Javaid fpu_s31_arm, 1063f57216cSOmair Javaid fpu_fpscr_arm, 107b4e95a50STamas Berghammer fpu_d0_arm, 108b4e95a50STamas Berghammer fpu_d1_arm, 109b4e95a50STamas Berghammer fpu_d2_arm, 110b4e95a50STamas Berghammer fpu_d3_arm, 111b4e95a50STamas Berghammer fpu_d4_arm, 112b4e95a50STamas Berghammer fpu_d5_arm, 113b4e95a50STamas Berghammer fpu_d6_arm, 114b4e95a50STamas Berghammer fpu_d7_arm, 115b4e95a50STamas Berghammer fpu_d8_arm, 116b4e95a50STamas Berghammer fpu_d9_arm, 117b4e95a50STamas Berghammer fpu_d10_arm, 118b4e95a50STamas Berghammer fpu_d11_arm, 119b4e95a50STamas Berghammer fpu_d12_arm, 120b4e95a50STamas Berghammer fpu_d13_arm, 121b4e95a50STamas Berghammer fpu_d14_arm, 122b4e95a50STamas Berghammer fpu_d15_arm, 123b4e95a50STamas Berghammer fpu_d16_arm, 124b4e95a50STamas Berghammer fpu_d17_arm, 125b4e95a50STamas Berghammer fpu_d18_arm, 126b4e95a50STamas Berghammer fpu_d19_arm, 127b4e95a50STamas Berghammer fpu_d20_arm, 128b4e95a50STamas Berghammer fpu_d21_arm, 129b4e95a50STamas Berghammer fpu_d22_arm, 130b4e95a50STamas Berghammer fpu_d23_arm, 131b4e95a50STamas Berghammer fpu_d24_arm, 132b4e95a50STamas Berghammer fpu_d25_arm, 133b4e95a50STamas Berghammer fpu_d26_arm, 134b4e95a50STamas Berghammer fpu_d27_arm, 135b4e95a50STamas Berghammer fpu_d28_arm, 136b4e95a50STamas Berghammer fpu_d29_arm, 137b4e95a50STamas Berghammer fpu_d30_arm, 138b4e95a50STamas Berghammer fpu_d31_arm, 139b4e95a50STamas Berghammer fpu_q0_arm, 140b4e95a50STamas Berghammer fpu_q1_arm, 141b4e95a50STamas Berghammer fpu_q2_arm, 142b4e95a50STamas Berghammer fpu_q3_arm, 143b4e95a50STamas Berghammer fpu_q4_arm, 144b4e95a50STamas Berghammer fpu_q5_arm, 145b4e95a50STamas Berghammer fpu_q6_arm, 146b4e95a50STamas Berghammer fpu_q7_arm, 147b4e95a50STamas Berghammer fpu_q8_arm, 148b4e95a50STamas Berghammer fpu_q9_arm, 149b4e95a50STamas Berghammer fpu_q10_arm, 150b4e95a50STamas Berghammer fpu_q11_arm, 151b4e95a50STamas Berghammer fpu_q12_arm, 152b4e95a50STamas Berghammer fpu_q13_arm, 153b4e95a50STamas Berghammer fpu_q14_arm, 154b4e95a50STamas Berghammer fpu_q15_arm, 1553f57216cSOmair Javaid LLDB_INVALID_REGNUM // register sets need to end with this flag 1563f57216cSOmair Javaid }; 1573f57216cSOmair Javaid static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \ 1583f57216cSOmair Javaid "g_fpu_regnums_arm has wrong number of register infos"); 1593f57216cSOmair Javaid 1603f57216cSOmair Javaid namespace { 1613f57216cSOmair Javaid // Number of register sets provided by this context. 1623f57216cSOmair Javaid enum 1633f57216cSOmair Javaid { 1643f57216cSOmair Javaid k_num_register_sets = 2 1653f57216cSOmair Javaid }; 1663f57216cSOmair Javaid } 1673f57216cSOmair Javaid 1683f57216cSOmair Javaid // Register sets for arm. 1693f57216cSOmair Javaid static const RegisterSet 1703f57216cSOmair Javaid g_reg_sets_arm[k_num_register_sets] = 1713f57216cSOmair Javaid { 1723f57216cSOmair Javaid { "General Purpose Registers", "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm }, 1733f57216cSOmair Javaid { "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm } 1743f57216cSOmair Javaid }; 1753f57216cSOmair Javaid 176e85e6021STamas Berghammer #if defined(__arm__) 177e85e6021STamas Berghammer 178068f8a7eSTamas Berghammer NativeRegisterContextLinux* 179068f8a7eSTamas Berghammer NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch, 1803f57216cSOmair Javaid NativeThreadProtocol &native_thread, 181068f8a7eSTamas Berghammer uint32_t concrete_frame_idx) 1823f57216cSOmair Javaid { 183068f8a7eSTamas Berghammer return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx); 184068f8a7eSTamas Berghammer } 185068f8a7eSTamas Berghammer 186e85e6021STamas Berghammer #endif // defined(__arm__) 187e85e6021STamas Berghammer 188068f8a7eSTamas Berghammer NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm (const ArchSpec& target_arch, 189068f8a7eSTamas Berghammer NativeThreadProtocol &native_thread, 190068f8a7eSTamas Berghammer uint32_t concrete_frame_idx) : 191068f8a7eSTamas Berghammer NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm(target_arch)) 192068f8a7eSTamas Berghammer { 193068f8a7eSTamas Berghammer switch (target_arch.GetMachine()) 1943f57216cSOmair Javaid { 1953f57216cSOmair Javaid case llvm::Triple::arm: 1963f57216cSOmair Javaid m_reg_info.num_registers = k_num_registers_arm; 1973f57216cSOmair Javaid m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; 1983f57216cSOmair Javaid m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; 1993f57216cSOmair Javaid m_reg_info.last_gpr = k_last_gpr_arm; 2003f57216cSOmair Javaid m_reg_info.first_fpr = k_first_fpr_arm; 2013f57216cSOmair Javaid m_reg_info.last_fpr = k_last_fpr_arm; 2023f57216cSOmair Javaid m_reg_info.first_fpr_v = fpu_s0_arm; 2033f57216cSOmair Javaid m_reg_info.last_fpr_v = fpu_s31_arm; 2043f57216cSOmair Javaid m_reg_info.gpr_flags = gpr_cpsr_arm; 2053f57216cSOmair Javaid break; 2063f57216cSOmair Javaid default: 2073f57216cSOmair Javaid assert(false && "Unhandled target architecture."); 2083f57216cSOmair Javaid break; 2093f57216cSOmair Javaid } 2103f57216cSOmair Javaid 2113f57216cSOmair Javaid ::memset(&m_fpr, 0, sizeof (m_fpr)); 2123f57216cSOmair Javaid ::memset(&m_gpr_arm, 0, sizeof (m_gpr_arm)); 2132441aecdSOmair Javaid ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs)); 2142441aecdSOmair Javaid 2152441aecdSOmair Javaid // 16 is just a maximum value, query hardware for actual watchpoint count 2162441aecdSOmair Javaid m_max_hwp_supported = 16; 2172441aecdSOmair Javaid m_max_hbp_supported = 16; 2182441aecdSOmair Javaid m_refresh_hwdebug_info = true; 2193f57216cSOmair Javaid } 2203f57216cSOmair Javaid 2213f57216cSOmair Javaid uint32_t 2223f57216cSOmair Javaid NativeRegisterContextLinux_arm::GetRegisterSetCount () const 2233f57216cSOmair Javaid { 2243f57216cSOmair Javaid return k_num_register_sets; 2253f57216cSOmair Javaid } 2263f57216cSOmair Javaid 2271f149204STamas Berghammer uint32_t 2281f149204STamas Berghammer NativeRegisterContextLinux_arm::GetUserRegisterCount() const 2291f149204STamas Berghammer { 2301f149204STamas Berghammer uint32_t count = 0; 2311f149204STamas Berghammer for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) 2321f149204STamas Berghammer count += g_reg_sets_arm[set_index].num_registers; 2331f149204STamas Berghammer return count; 2341f149204STamas Berghammer } 2351f149204STamas Berghammer 2363f57216cSOmair Javaid const RegisterSet * 2373f57216cSOmair Javaid NativeRegisterContextLinux_arm::GetRegisterSet (uint32_t set_index) const 2383f57216cSOmair Javaid { 2393f57216cSOmair Javaid if (set_index < k_num_register_sets) 2403f57216cSOmair Javaid return &g_reg_sets_arm[set_index]; 2413f57216cSOmair Javaid 2423f57216cSOmair Javaid return nullptr; 2433f57216cSOmair Javaid } 2443f57216cSOmair Javaid 2453f57216cSOmair Javaid Error 2463f57216cSOmair Javaid NativeRegisterContextLinux_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) 2473f57216cSOmair Javaid { 2483f57216cSOmair Javaid Error error; 2493f57216cSOmair Javaid 2503f57216cSOmair Javaid if (!reg_info) 2513f57216cSOmair Javaid { 2523f57216cSOmair Javaid error.SetErrorString ("reg_info NULL"); 2533f57216cSOmair Javaid return error; 2543f57216cSOmair Javaid } 2553f57216cSOmair Javaid 2563f57216cSOmair Javaid const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 2573f57216cSOmair Javaid 2583f57216cSOmair Javaid if (IsFPR(reg)) 2593f57216cSOmair Javaid { 260068f8a7eSTamas Berghammer error = ReadFPR(); 261068f8a7eSTamas Berghammer if (error.Fail()) 2623f57216cSOmair Javaid return error; 2633f57216cSOmair Javaid } 2643f57216cSOmair Javaid else 2653f57216cSOmair Javaid { 2663f57216cSOmair Javaid uint32_t full_reg = reg; 2673f57216cSOmair Javaid bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 2683f57216cSOmair Javaid 2693f57216cSOmair Javaid if (is_subreg) 2703f57216cSOmair Javaid { 2713f57216cSOmair Javaid // Read the full aligned 64-bit register. 2723f57216cSOmair Javaid full_reg = reg_info->invalidate_regs[0]; 2733f57216cSOmair Javaid } 2743f57216cSOmair Javaid 2753f57216cSOmair Javaid error = ReadRegisterRaw(full_reg, reg_value); 2763f57216cSOmair Javaid 2773f57216cSOmair Javaid if (error.Success ()) 2783f57216cSOmair Javaid { 2793f57216cSOmair Javaid // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. 2803f57216cSOmair Javaid if (is_subreg && (reg_info->byte_offset & 0x1)) 2813f57216cSOmair Javaid reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); 2823f57216cSOmair Javaid 2833f57216cSOmair Javaid // If our return byte size was greater than the return value reg size, then 2843f57216cSOmair Javaid // use the type specified by reg_info rather than the uint64_t default 2853f57216cSOmair Javaid if (reg_value.GetByteSize() > reg_info->byte_size) 2863f57216cSOmair Javaid reg_value.SetType(reg_info); 2873f57216cSOmair Javaid } 2883f57216cSOmair Javaid return error; 2893f57216cSOmair Javaid } 2903f57216cSOmair Javaid 2913f57216cSOmair Javaid // Get pointer to m_fpr variable and set the data from it. 292c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 293c40e7b17STamas Berghammer assert (fpr_offset < sizeof m_fpr); 294c40e7b17STamas Berghammer uint8_t *src = (uint8_t *)&m_fpr + fpr_offset; 2953f57216cSOmair Javaid switch (reg_info->byte_size) 2963f57216cSOmair Javaid { 2973f57216cSOmair Javaid case 2: 2983f57216cSOmair Javaid reg_value.SetUInt16(*(uint16_t *)src); 2993f57216cSOmair Javaid break; 3003f57216cSOmair Javaid case 4: 3013f57216cSOmair Javaid reg_value.SetUInt32(*(uint32_t *)src); 3023f57216cSOmair Javaid break; 3033f57216cSOmair Javaid case 8: 3043f57216cSOmair Javaid reg_value.SetUInt64(*(uint64_t *)src); 3053f57216cSOmair Javaid break; 306b4e95a50STamas Berghammer case 16: 307b4e95a50STamas Berghammer reg_value.SetBytes(src, 16, GetByteOrder()); 308b4e95a50STamas Berghammer break; 3093f57216cSOmair Javaid default: 3103f57216cSOmair Javaid assert(false && "Unhandled data size."); 3113f57216cSOmair Javaid error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size); 3123f57216cSOmair Javaid break; 3133f57216cSOmair Javaid } 3143f57216cSOmair Javaid 3153f57216cSOmair Javaid return error; 3163f57216cSOmair Javaid } 3173f57216cSOmair Javaid 3183f57216cSOmair Javaid Error 3193f57216cSOmair Javaid NativeRegisterContextLinux_arm::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) 3203f57216cSOmair Javaid { 3213f57216cSOmair Javaid if (!reg_info) 3223f57216cSOmair Javaid return Error ("reg_info NULL"); 3233f57216cSOmair Javaid 3243f57216cSOmair Javaid const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 3253f57216cSOmair Javaid if (reg_index == LLDB_INVALID_REGNUM) 3263f57216cSOmair Javaid return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>"); 3273f57216cSOmair Javaid 3283f57216cSOmair Javaid if (IsGPR(reg_index)) 3293f57216cSOmair Javaid return WriteRegisterRaw(reg_index, reg_value); 3303f57216cSOmair Javaid 3313f57216cSOmair Javaid if (IsFPR(reg_index)) 3323f57216cSOmair Javaid { 3333f57216cSOmair Javaid // Get pointer to m_fpr variable and set the data to it. 334c40e7b17STamas Berghammer uint32_t fpr_offset = CalculateFprOffset(reg_info); 335c40e7b17STamas Berghammer assert (fpr_offset < sizeof m_fpr); 336c40e7b17STamas Berghammer uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset; 3373f57216cSOmair Javaid switch (reg_info->byte_size) 3383f57216cSOmair Javaid { 3393f57216cSOmair Javaid case 2: 3403f57216cSOmair Javaid *(uint16_t *)dst = reg_value.GetAsUInt16(); 3413f57216cSOmair Javaid break; 3423f57216cSOmair Javaid case 4: 3433f57216cSOmair Javaid *(uint32_t *)dst = reg_value.GetAsUInt32(); 3443f57216cSOmair Javaid break; 3453f57216cSOmair Javaid case 8: 3463f57216cSOmair Javaid *(uint64_t *)dst = reg_value.GetAsUInt64(); 3473f57216cSOmair Javaid break; 3483f57216cSOmair Javaid default: 3493f57216cSOmair Javaid assert(false && "Unhandled data size."); 3503f57216cSOmair Javaid return Error ("unhandled register data size %" PRIu32, reg_info->byte_size); 3513f57216cSOmair Javaid } 3523f57216cSOmair Javaid 353068f8a7eSTamas Berghammer Error error = WriteFPR(); 354068f8a7eSTamas Berghammer if (error.Fail()) 355068f8a7eSTamas Berghammer return error; 3563f57216cSOmair Javaid 3573f57216cSOmair Javaid return Error (); 3583f57216cSOmair Javaid } 3593f57216cSOmair Javaid 3603f57216cSOmair Javaid return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown"); 3613f57216cSOmair Javaid } 3623f57216cSOmair Javaid 3633f57216cSOmair Javaid Error 3643f57216cSOmair Javaid NativeRegisterContextLinux_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) 3653f57216cSOmair Javaid { 3663f57216cSOmair Javaid Error error; 3673f57216cSOmair Javaid 3683f57216cSOmair Javaid data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); 3693f57216cSOmair Javaid if (!data_sp) 370bef47e49SGreg Clayton return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, (uint64_t)REG_CONTEXT_SIZE); 3713f57216cSOmair Javaid 372068f8a7eSTamas Berghammer error = ReadGPR(); 373068f8a7eSTamas Berghammer if (error.Fail()) 3743f57216cSOmair Javaid return error; 3753f57216cSOmair Javaid 376068f8a7eSTamas Berghammer error = ReadFPR(); 377068f8a7eSTamas Berghammer if (error.Fail()) 3783f57216cSOmair Javaid return error; 3793f57216cSOmair Javaid 3803f57216cSOmair Javaid uint8_t *dst = data_sp->GetBytes (); 3813f57216cSOmair Javaid if (dst == nullptr) 3823f57216cSOmair Javaid { 383bef47e49SGreg Clayton error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", (uint64_t)REG_CONTEXT_SIZE); 3843f57216cSOmair Javaid return error; 3853f57216cSOmair Javaid } 3863f57216cSOmair Javaid 3873f57216cSOmair Javaid ::memcpy (dst, &m_gpr_arm, GetGPRSize()); 3883f57216cSOmair Javaid dst += GetGPRSize(); 3893f57216cSOmair Javaid ::memcpy (dst, &m_fpr, sizeof(m_fpr)); 3903f57216cSOmair Javaid 3913f57216cSOmair Javaid return error; 3923f57216cSOmair Javaid } 3933f57216cSOmair Javaid 3943f57216cSOmair Javaid Error 3953f57216cSOmair Javaid NativeRegisterContextLinux_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) 3963f57216cSOmair Javaid { 3973f57216cSOmair Javaid Error error; 3983f57216cSOmair Javaid 3993f57216cSOmair Javaid if (!data_sp) 4003f57216cSOmair Javaid { 4013f57216cSOmair Javaid error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__); 4023f57216cSOmair Javaid return error; 4033f57216cSOmair Javaid } 4043f57216cSOmair Javaid 4053f57216cSOmair Javaid if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) 4063f57216cSOmair Javaid { 407bef47e49SGreg Clayton error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize ()); 4083f57216cSOmair Javaid return error; 4093f57216cSOmair Javaid } 4103f57216cSOmair Javaid 4113f57216cSOmair Javaid 4123f57216cSOmair Javaid uint8_t *src = data_sp->GetBytes (); 4133f57216cSOmair Javaid if (src == nullptr) 4143f57216cSOmair Javaid { 4153f57216cSOmair Javaid error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); 4163f57216cSOmair Javaid return error; 4173f57216cSOmair Javaid } 4183f57216cSOmair Javaid ::memcpy (&m_gpr_arm, src, GetRegisterInfoInterface ().GetGPRSize ()); 4193f57216cSOmair Javaid 420068f8a7eSTamas Berghammer error = WriteGPR(); 421068f8a7eSTamas Berghammer if (error.Fail()) 4223f57216cSOmair Javaid return error; 4233f57216cSOmair Javaid 4243f57216cSOmair Javaid src += GetRegisterInfoInterface ().GetGPRSize (); 4253f57216cSOmair Javaid ::memcpy (&m_fpr, src, sizeof(m_fpr)); 4263f57216cSOmair Javaid 427068f8a7eSTamas Berghammer error = WriteFPR(); 4283f57216cSOmair Javaid if (error.Fail()) 4293f57216cSOmair Javaid return error; 4303f57216cSOmair Javaid 4313f57216cSOmair Javaid return error; 4323f57216cSOmair Javaid } 4333f57216cSOmair Javaid 4343f57216cSOmair Javaid bool 4353f57216cSOmair Javaid NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const 4363f57216cSOmair Javaid { 4373f57216cSOmair Javaid return reg <= m_reg_info.last_gpr; // GPR's come first. 4383f57216cSOmair Javaid } 4393f57216cSOmair Javaid 4403f57216cSOmair Javaid bool 4413f57216cSOmair Javaid NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const 4423f57216cSOmair Javaid { 4433f57216cSOmair Javaid return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 4443f57216cSOmair Javaid } 4453f57216cSOmair Javaid 4462441aecdSOmair Javaid uint32_t 4472441aecdSOmair Javaid NativeRegisterContextLinux_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) 4482441aecdSOmair Javaid { 4492441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 4502441aecdSOmair Javaid 4512441aecdSOmair Javaid if (log) 4522441aecdSOmair Javaid log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 4532441aecdSOmair Javaid 4542441aecdSOmair Javaid Error error; 4552441aecdSOmair Javaid 4562441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 4572441aecdSOmair Javaid error = ReadHardwareDebugInfo (); 4582441aecdSOmair Javaid 4592441aecdSOmair Javaid if (error.Fail()) 4602441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 4612441aecdSOmair Javaid 4622441aecdSOmair Javaid uint32_t control_value = 0, bp_index = 0; 4632441aecdSOmair Javaid 4642441aecdSOmair Javaid // Check if size has a valid hardware breakpoint length. 4652441aecdSOmair Javaid // Thumb instructions are 2-bytes but we have no way here to determine 4662441aecdSOmair Javaid // if target address is a thumb or arm instruction. 4672441aecdSOmair Javaid // TODO: Add support for setting thumb mode hardware breakpoints 4682441aecdSOmair Javaid if (size != 4 && size != 2) 4692441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 4702441aecdSOmair Javaid 4712441aecdSOmair Javaid // Setup control value 4722441aecdSOmair Javaid // Make the byte_mask into a valid Byte Address Select mask 4732441aecdSOmair Javaid control_value = 0xfu << 5; 4742441aecdSOmair Javaid 4752441aecdSOmair Javaid // Enable this breakpoint and make it stop in privileged or user mode; 4762441aecdSOmair Javaid control_value |= 7; 4772441aecdSOmair Javaid 4782441aecdSOmair Javaid // Make sure bits 1:0 are clear in our address 4792441aecdSOmair Javaid // This should be different once we support thumb here. 4802441aecdSOmair Javaid addr &= ~((lldb::addr_t)3); 4812441aecdSOmair Javaid 4822441aecdSOmair Javaid // Iterate over stored hardware breakpoints 4832441aecdSOmair Javaid // Find a free bp_index or update reference count if duplicate. 4842441aecdSOmair Javaid bp_index = LLDB_INVALID_INDEX32; 4852441aecdSOmair Javaid 4862441aecdSOmair Javaid for (uint32_t i = 0; i < m_max_hbp_supported; i++) 4872441aecdSOmair Javaid { 4882441aecdSOmair Javaid if ((m_hbr_regs[i].control & 1) == 0) 4892441aecdSOmair Javaid { 4902441aecdSOmair Javaid bp_index = i; // Mark last free slot 4912441aecdSOmair Javaid } 4922441aecdSOmair Javaid else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value) 4932441aecdSOmair Javaid { 4942441aecdSOmair Javaid bp_index = i; // Mark duplicate index 4952441aecdSOmair Javaid break; // Stop searching here 4962441aecdSOmair Javaid } 4972441aecdSOmair Javaid } 4982441aecdSOmair Javaid 4992441aecdSOmair Javaid if (bp_index == LLDB_INVALID_INDEX32) 5002441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5012441aecdSOmair Javaid 5024aa984c1SOmair Javaid // Add new or update existing breakpoint 5032441aecdSOmair Javaid if ((m_hbr_regs[bp_index].control & 1) == 0) 5042441aecdSOmair Javaid { 5052441aecdSOmair Javaid m_hbr_regs[bp_index].address = addr; 5062441aecdSOmair Javaid m_hbr_regs[bp_index].control = control_value; 5072441aecdSOmair Javaid m_hbr_regs[bp_index].refcount = 1; 5082441aecdSOmair Javaid 5092441aecdSOmair Javaid // PTRACE call to set corresponding hardware breakpoint register. 5102441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index); 5112441aecdSOmair Javaid 5122441aecdSOmair Javaid if (error.Fail()) 513d5510d1eSOmair Javaid { 514d5510d1eSOmair Javaid m_hbr_regs[bp_index].address = 0; 515d5510d1eSOmair Javaid m_hbr_regs[bp_index].control &= ~1; 516d5510d1eSOmair Javaid m_hbr_regs[bp_index].refcount = 0; 517d5510d1eSOmair Javaid 5182441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5192441aecdSOmair Javaid } 520d5510d1eSOmair Javaid } 5212441aecdSOmair Javaid else 5222441aecdSOmair Javaid m_hbr_regs[bp_index].refcount++; 5232441aecdSOmair Javaid 5242441aecdSOmair Javaid return bp_index; 5252441aecdSOmair Javaid } 5262441aecdSOmair Javaid 5272441aecdSOmair Javaid bool 5282441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearHardwareBreakpoint (uint32_t hw_idx) 5292441aecdSOmair Javaid { 5302441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 5312441aecdSOmair Javaid 5322441aecdSOmair Javaid if (log) 5332441aecdSOmair Javaid log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 5342441aecdSOmair Javaid 5352441aecdSOmair Javaid Error error; 5362441aecdSOmair Javaid 5372441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 5382441aecdSOmair Javaid error = ReadHardwareDebugInfo (); 5392441aecdSOmair Javaid 5402441aecdSOmair Javaid if (error.Fail()) 5414aa984c1SOmair Javaid return false; 5422441aecdSOmair Javaid 5432441aecdSOmair Javaid if (hw_idx >= m_max_hbp_supported) 5442441aecdSOmair Javaid return false; 5452441aecdSOmair Javaid 5462441aecdSOmair Javaid // Update reference count if multiple references. 5472441aecdSOmair Javaid if (m_hbr_regs[hw_idx].refcount > 1) 5482441aecdSOmair Javaid { 5492441aecdSOmair Javaid m_hbr_regs[hw_idx].refcount--; 5502441aecdSOmair Javaid return true; 5512441aecdSOmair Javaid } 5522441aecdSOmair Javaid else if (m_hbr_regs[hw_idx].refcount == 1) 5532441aecdSOmair Javaid { 554d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 555d5510d1eSOmair Javaid lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; 556d5510d1eSOmair Javaid uint32_t tempControl = m_hbr_regs[hw_idx].control; 557d5510d1eSOmair Javaid uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount; 558d5510d1eSOmair Javaid 5592441aecdSOmair Javaid m_hbr_regs[hw_idx].control &= ~1; 5602441aecdSOmair Javaid m_hbr_regs[hw_idx].address = 0; 5612441aecdSOmair Javaid m_hbr_regs[hw_idx].refcount = 0; 5622441aecdSOmair Javaid 5632441aecdSOmair Javaid // PTRACE call to clear corresponding hardware breakpoint register. 5642441aecdSOmair Javaid WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx); 5652441aecdSOmair Javaid 5662441aecdSOmair Javaid if (error.Fail()) 567d5510d1eSOmair Javaid { 568d5510d1eSOmair Javaid m_hbr_regs[hw_idx].control = tempControl; 569d5510d1eSOmair Javaid m_hbr_regs[hw_idx].address = tempAddr; 570d5510d1eSOmair Javaid m_hbr_regs[hw_idx].refcount = tempRefCount; 571d5510d1eSOmair Javaid 5724aa984c1SOmair Javaid return false; 573d5510d1eSOmair Javaid } 5742441aecdSOmair Javaid 5752441aecdSOmair Javaid return true; 5762441aecdSOmair Javaid } 5772441aecdSOmair Javaid 5782441aecdSOmair Javaid return false; 5792441aecdSOmair Javaid } 5802441aecdSOmair Javaid 5812441aecdSOmair Javaid uint32_t 5822441aecdSOmair Javaid NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints () 5832441aecdSOmair Javaid { 5842441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 5852441aecdSOmair Javaid 5862441aecdSOmair Javaid if (log) 5872441aecdSOmair Javaid log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 5882441aecdSOmair Javaid 5892441aecdSOmair Javaid Error error; 5902441aecdSOmair Javaid 5912441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 5922441aecdSOmair Javaid error = ReadHardwareDebugInfo (); 5932441aecdSOmair Javaid 5942441aecdSOmair Javaid if (error.Fail()) 5952441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 5962441aecdSOmair Javaid 5972441aecdSOmair Javaid return m_max_hwp_supported; 5982441aecdSOmair Javaid } 5992441aecdSOmair Javaid 6002441aecdSOmair Javaid uint32_t 6012441aecdSOmair Javaid NativeRegisterContextLinux_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) 6022441aecdSOmair Javaid { 6032441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 6042441aecdSOmair Javaid 6052441aecdSOmair Javaid if (log) 6062441aecdSOmair Javaid log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 6072441aecdSOmair Javaid 6082441aecdSOmair Javaid Error error; 6092441aecdSOmair Javaid 6102441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 6112441aecdSOmair Javaid error = ReadHardwareDebugInfo (); 6122441aecdSOmair Javaid 6132441aecdSOmair Javaid if (error.Fail()) 6142441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 6152441aecdSOmair Javaid 6162441aecdSOmair Javaid uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0; 617*c6dc90efSOmair Javaid lldb::addr_t real_addr = addr; 6182441aecdSOmair Javaid 6192441aecdSOmair Javaid // Check if we are setting watchpoint other than read/write/access 6202441aecdSOmair Javaid // Also update watchpoint flag to match Arm write-read bit configuration. 6212441aecdSOmair Javaid switch (watch_flags) 6222441aecdSOmair Javaid { 6232441aecdSOmair Javaid case 1: 6242441aecdSOmair Javaid watch_flags = 2; 6252441aecdSOmair Javaid break; 6262441aecdSOmair Javaid case 2: 6272441aecdSOmair Javaid watch_flags = 1; 6282441aecdSOmair Javaid break; 6292441aecdSOmair Javaid case 3: 6302441aecdSOmair Javaid break; 6312441aecdSOmair Javaid default: 6322441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 6332441aecdSOmair Javaid } 6342441aecdSOmair Javaid 6352441aecdSOmair Javaid // Can't watch zero bytes 6362441aecdSOmair Javaid // Can't watch more than 4 bytes per WVR/WCR pair 6372441aecdSOmair Javaid 6382441aecdSOmair Javaid if (size == 0 || size > 4) 6392441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 6402441aecdSOmair Javaid 641*c6dc90efSOmair Javaid // Check 4-byte alignment for hardware watchpoint target address. 642*c6dc90efSOmair Javaid // Below is a hack to recalculate address and size in order to 643*c6dc90efSOmair Javaid // make sure we can watch non 4-byte alligned addresses as well. 644*c6dc90efSOmair Javaid if (addr & 0x03) 645*c6dc90efSOmair Javaid { 646*c6dc90efSOmair Javaid uint8_t watch_mask = (addr & 0x03) + size; 647*c6dc90efSOmair Javaid 648*c6dc90efSOmair Javaid if (watch_mask > 0x04) 649*c6dc90efSOmair Javaid return LLDB_INVALID_INDEX32; 650*c6dc90efSOmair Javaid else if (watch_mask <= 0x02) 651*c6dc90efSOmair Javaid size = 2; 652*c6dc90efSOmair Javaid else if (watch_mask <= 0x04) 653*c6dc90efSOmair Javaid size = 4; 654*c6dc90efSOmair Javaid 655*c6dc90efSOmair Javaid addr = addr & (~0x03); 656*c6dc90efSOmair Javaid } 657*c6dc90efSOmair Javaid 6582441aecdSOmair Javaid // We can only watch up to four bytes that follow a 4 byte aligned address 6592441aecdSOmair Javaid // per watchpoint register pair, so make sure we can properly encode this. 6602441aecdSOmair Javaid addr_word_offset = addr % 4; 6612441aecdSOmair Javaid byte_mask = ((1u << size) - 1u) << addr_word_offset; 6622441aecdSOmair Javaid 6632441aecdSOmair Javaid // Check if we need multiple watchpoint register 6642441aecdSOmair Javaid if (byte_mask > 0xfu) 6652441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 6662441aecdSOmair Javaid 6672441aecdSOmair Javaid // Setup control value 6682441aecdSOmair Javaid // Make the byte_mask into a valid Byte Address Select mask 6692441aecdSOmair Javaid control_value = byte_mask << 5; 6702441aecdSOmair Javaid 6712441aecdSOmair Javaid //Turn on appropriate watchpoint flags read or write 6722441aecdSOmair Javaid control_value |= (watch_flags << 3); 6732441aecdSOmair Javaid 6742441aecdSOmair Javaid // Enable this watchpoint and make it stop in privileged or user mode; 6752441aecdSOmair Javaid control_value |= 7; 6762441aecdSOmair Javaid 6772441aecdSOmair Javaid // Make sure bits 1:0 are clear in our address 6782441aecdSOmair Javaid addr &= ~((lldb::addr_t)3); 6792441aecdSOmair Javaid 6802441aecdSOmair Javaid // Iterate over stored watchpoints 6812441aecdSOmair Javaid // Find a free wp_index or update reference count if duplicate. 6822441aecdSOmair Javaid wp_index = LLDB_INVALID_INDEX32; 6832441aecdSOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 6842441aecdSOmair Javaid { 6852441aecdSOmair Javaid if ((m_hwp_regs[i].control & 1) == 0) 6862441aecdSOmair Javaid { 6872441aecdSOmair Javaid wp_index = i; // Mark last free slot 6882441aecdSOmair Javaid } 6892441aecdSOmair Javaid else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value) 6902441aecdSOmair Javaid { 6912441aecdSOmair Javaid wp_index = i; // Mark duplicate index 6922441aecdSOmair Javaid break; // Stop searching here 6932441aecdSOmair Javaid } 6942441aecdSOmair Javaid } 6952441aecdSOmair Javaid 6962441aecdSOmair Javaid if (wp_index == LLDB_INVALID_INDEX32) 6972441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 6982441aecdSOmair Javaid 6992441aecdSOmair Javaid // Add new or update existing watchpoint 7002441aecdSOmair Javaid if ((m_hwp_regs[wp_index].control & 1) == 0) 7012441aecdSOmair Javaid { 7022441aecdSOmair Javaid // Update watchpoint in local cache 703*c6dc90efSOmair Javaid m_hwp_regs[wp_index].real_addr = real_addr; 7042441aecdSOmair Javaid m_hwp_regs[wp_index].address = addr; 7052441aecdSOmair Javaid m_hwp_regs[wp_index].control = control_value; 7062441aecdSOmair Javaid m_hwp_regs[wp_index].refcount = 1; 7072441aecdSOmair Javaid 7082441aecdSOmair Javaid // PTRACE call to set corresponding watchpoint register. 7092441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); 7102441aecdSOmair Javaid 7112441aecdSOmair Javaid if (error.Fail()) 712d5510d1eSOmair Javaid { 713d5510d1eSOmair Javaid m_hwp_regs[wp_index].address = 0; 714d5510d1eSOmair Javaid m_hwp_regs[wp_index].control &= ~1; 715d5510d1eSOmair Javaid m_hwp_regs[wp_index].refcount = 0; 716d5510d1eSOmair Javaid 7172441aecdSOmair Javaid return LLDB_INVALID_INDEX32; 7182441aecdSOmair Javaid } 719d5510d1eSOmair Javaid } 7202441aecdSOmair Javaid else 7212441aecdSOmair Javaid m_hwp_regs[wp_index].refcount++; 7222441aecdSOmair Javaid 7232441aecdSOmair Javaid return wp_index; 7242441aecdSOmair Javaid } 7252441aecdSOmair Javaid 7262441aecdSOmair Javaid bool 7272441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearHardwareWatchpoint (uint32_t wp_index) 7282441aecdSOmair Javaid { 7292441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 7302441aecdSOmair Javaid 7312441aecdSOmair Javaid if (log) 7322441aecdSOmair Javaid log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 7332441aecdSOmair Javaid 7342441aecdSOmair Javaid Error error; 7352441aecdSOmair Javaid 7362441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 7372441aecdSOmair Javaid error = ReadHardwareDebugInfo (); 7382441aecdSOmair Javaid 7392441aecdSOmair Javaid if (error.Fail()) 7404aa984c1SOmair Javaid return false; 7412441aecdSOmair Javaid 7422441aecdSOmair Javaid if (wp_index >= m_max_hwp_supported) 7432441aecdSOmair Javaid return false; 7442441aecdSOmair Javaid 7452441aecdSOmair Javaid // Update reference count if multiple references. 7462441aecdSOmair Javaid if (m_hwp_regs[wp_index].refcount > 1) 7472441aecdSOmair Javaid { 7482441aecdSOmair Javaid m_hwp_regs[wp_index].refcount--; 7492441aecdSOmair Javaid return true; 7502441aecdSOmair Javaid } 7512441aecdSOmair Javaid else if (m_hwp_regs[wp_index].refcount == 1) 7522441aecdSOmair Javaid { 753d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 754d5510d1eSOmair Javaid lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 755d5510d1eSOmair Javaid uint32_t tempControl = m_hwp_regs[wp_index].control; 756d5510d1eSOmair Javaid uint32_t tempRefCount = m_hwp_regs[wp_index].refcount; 757d5510d1eSOmair Javaid 7582441aecdSOmair Javaid // Update watchpoint in local cache 7592441aecdSOmair Javaid m_hwp_regs[wp_index].control &= ~1; 7602441aecdSOmair Javaid m_hwp_regs[wp_index].address = 0; 7612441aecdSOmair Javaid m_hwp_regs[wp_index].refcount = 0; 7622441aecdSOmair Javaid 7632441aecdSOmair Javaid // Ptrace call to update hardware debug registers 7642441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); 7652441aecdSOmair Javaid 7662441aecdSOmair Javaid if (error.Fail()) 767d5510d1eSOmair Javaid { 768d5510d1eSOmair Javaid m_hwp_regs[wp_index].control = tempControl; 769d5510d1eSOmair Javaid m_hwp_regs[wp_index].address = tempAddr; 770d5510d1eSOmair Javaid m_hwp_regs[wp_index].refcount = tempRefCount; 771d5510d1eSOmair Javaid 7722441aecdSOmair Javaid return false; 773d5510d1eSOmair Javaid } 7742441aecdSOmair Javaid 7752441aecdSOmair Javaid return true; 7762441aecdSOmair Javaid } 7772441aecdSOmair Javaid 7782441aecdSOmair Javaid return false; 7792441aecdSOmair Javaid } 7802441aecdSOmair Javaid 7812441aecdSOmair Javaid Error 7822441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints () 7832441aecdSOmair Javaid { 7842441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 7852441aecdSOmair Javaid 7862441aecdSOmair Javaid if (log) 7872441aecdSOmair Javaid log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 7882441aecdSOmair Javaid 7892441aecdSOmair Javaid Error error; 7902441aecdSOmair Javaid 7912441aecdSOmair Javaid // Read hardware breakpoint and watchpoint information. 7922441aecdSOmair Javaid error = ReadHardwareDebugInfo (); 7932441aecdSOmair Javaid 7942441aecdSOmair Javaid if (error.Fail()) 7952441aecdSOmair Javaid return error; 7962441aecdSOmair Javaid 797d5510d1eSOmair Javaid lldb::addr_t tempAddr = 0; 798d5510d1eSOmair Javaid uint32_t tempControl = 0, tempRefCount = 0; 799d5510d1eSOmair Javaid 8002441aecdSOmair Javaid for (uint32_t i = 0; i < m_max_hwp_supported; i++) 8012441aecdSOmair Javaid { 8022441aecdSOmair Javaid if (m_hwp_regs[i].control & 0x01) 8032441aecdSOmair Javaid { 804d5510d1eSOmair Javaid // Create a backup we can revert to in case of failure. 805d5510d1eSOmair Javaid tempAddr = m_hwp_regs[i].address; 806d5510d1eSOmair Javaid tempControl = m_hwp_regs[i].control; 807d5510d1eSOmair Javaid tempRefCount = m_hwp_regs[i].refcount; 808d5510d1eSOmair Javaid 8092441aecdSOmair Javaid // Clear watchpoints in local cache 8102441aecdSOmair Javaid m_hwp_regs[i].control &= ~1; 8112441aecdSOmair Javaid m_hwp_regs[i].address = 0; 8122441aecdSOmair Javaid m_hwp_regs[i].refcount = 0; 8132441aecdSOmair Javaid 8142441aecdSOmair Javaid // Ptrace call to update hardware debug registers 8152441aecdSOmair Javaid error = WriteHardwareDebugRegs(eDREGTypeWATCH, i); 8162441aecdSOmair Javaid 8172441aecdSOmair Javaid if (error.Fail()) 818d5510d1eSOmair Javaid { 819d5510d1eSOmair Javaid m_hwp_regs[i].control = tempControl; 820d5510d1eSOmair Javaid m_hwp_regs[i].address = tempAddr; 821d5510d1eSOmair Javaid m_hwp_regs[i].refcount = tempRefCount; 822d5510d1eSOmair Javaid 8232441aecdSOmair Javaid return error; 8242441aecdSOmair Javaid } 8252441aecdSOmair Javaid } 826d5510d1eSOmair Javaid } 8272441aecdSOmair Javaid 8282441aecdSOmair Javaid return Error(); 8292441aecdSOmair Javaid } 8302441aecdSOmair Javaid 8312441aecdSOmair Javaid uint32_t 8322441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) 8332441aecdSOmair Javaid { 8342441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 8352441aecdSOmair Javaid 8362441aecdSOmair Javaid if (log) 8372441aecdSOmair Javaid log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 8382441aecdSOmair Javaid 8392441aecdSOmair Javaid switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) 8402441aecdSOmair Javaid { 8412441aecdSOmair Javaid case 0x01: 8422441aecdSOmair Javaid return 1; 8432441aecdSOmair Javaid case 0x03: 8442441aecdSOmair Javaid return 2; 8452441aecdSOmair Javaid case 0x07: 8462441aecdSOmair Javaid return 3; 8472441aecdSOmair Javaid case 0x0f: 8482441aecdSOmair Javaid return 4; 8492441aecdSOmair Javaid default: 8502441aecdSOmair Javaid return 0; 8512441aecdSOmair Javaid } 8522441aecdSOmair Javaid } 8532441aecdSOmair Javaid bool 8542441aecdSOmair Javaid NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) 8552441aecdSOmair Javaid { 8562441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 8572441aecdSOmair Javaid 8582441aecdSOmair Javaid if (log) 8592441aecdSOmair Javaid log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 8602441aecdSOmair Javaid 8612441aecdSOmair Javaid if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 8622441aecdSOmair Javaid return true; 8632441aecdSOmair Javaid else 8642441aecdSOmair Javaid return false; 8652441aecdSOmair Javaid } 8662441aecdSOmair Javaid 8672441aecdSOmair Javaid Error 8682441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) 8692441aecdSOmair Javaid { 8702441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 8712441aecdSOmair Javaid 8722441aecdSOmair Javaid if (log) 8732441aecdSOmair Javaid log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 8742441aecdSOmair Javaid 8752441aecdSOmair Javaid uint32_t watch_size; 8762441aecdSOmair Javaid lldb::addr_t watch_addr; 8772441aecdSOmair Javaid 8782441aecdSOmair Javaid for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) 8792441aecdSOmair Javaid { 8802441aecdSOmair Javaid watch_size = GetWatchpointSize (wp_index); 8812441aecdSOmair Javaid watch_addr = m_hwp_regs[wp_index].address; 8822441aecdSOmair Javaid 8832441aecdSOmair Javaid if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) 8842441aecdSOmair Javaid && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) 8852441aecdSOmair Javaid { 886*c6dc90efSOmair Javaid m_hwp_regs[wp_index].hit_addr = trap_addr; 8872441aecdSOmair Javaid return Error(); 8882441aecdSOmair Javaid } 8892441aecdSOmair Javaid } 8902441aecdSOmair Javaid 8912441aecdSOmair Javaid wp_index = LLDB_INVALID_INDEX32; 8922441aecdSOmair Javaid return Error(); 8932441aecdSOmair Javaid } 8942441aecdSOmair Javaid 8952441aecdSOmair Javaid lldb::addr_t 8962441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointAddress (uint32_t wp_index) 8972441aecdSOmair Javaid { 8982441aecdSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 8992441aecdSOmair Javaid 9002441aecdSOmair Javaid if (log) 9012441aecdSOmair Javaid log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 9022441aecdSOmair Javaid 9032441aecdSOmair Javaid if (wp_index >= m_max_hwp_supported) 9042441aecdSOmair Javaid return LLDB_INVALID_ADDRESS; 9052441aecdSOmair Javaid 9062441aecdSOmair Javaid if (WatchpointIsEnabled(wp_index)) 907*c6dc90efSOmair Javaid return m_hwp_regs[wp_index].real_addr; 908*c6dc90efSOmair Javaid else 909*c6dc90efSOmair Javaid return LLDB_INVALID_ADDRESS; 910*c6dc90efSOmair Javaid } 911*c6dc90efSOmair Javaid 912*c6dc90efSOmair Javaid lldb::addr_t 913*c6dc90efSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointHitAddress (uint32_t wp_index) 914*c6dc90efSOmair Javaid { 915*c6dc90efSOmair Javaid Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 916*c6dc90efSOmair Javaid 917*c6dc90efSOmair Javaid if (log) 918*c6dc90efSOmair Javaid log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); 919*c6dc90efSOmair Javaid 920*c6dc90efSOmair Javaid if (wp_index >= m_max_hwp_supported) 921*c6dc90efSOmair Javaid return LLDB_INVALID_ADDRESS; 922*c6dc90efSOmair Javaid 923*c6dc90efSOmair Javaid if (WatchpointIsEnabled(wp_index)) 924*c6dc90efSOmair Javaid return m_hwp_regs[wp_index].hit_addr; 9252441aecdSOmair Javaid else 9262441aecdSOmair Javaid return LLDB_INVALID_ADDRESS; 9272441aecdSOmair Javaid } 9282441aecdSOmair Javaid 9292441aecdSOmair Javaid Error 9302441aecdSOmair Javaid NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() 9312441aecdSOmair Javaid { 9322441aecdSOmair Javaid Error error; 9332441aecdSOmair Javaid 9342441aecdSOmair Javaid if (!m_refresh_hwdebug_info) 9352441aecdSOmair Javaid { 9362441aecdSOmair Javaid return Error(); 9372441aecdSOmair Javaid } 9382441aecdSOmair Javaid 9392441aecdSOmair Javaid unsigned int cap_val; 9402441aecdSOmair Javaid 9412441aecdSOmair Javaid error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), nullptr, &cap_val, sizeof(unsigned int)); 9422441aecdSOmair Javaid 9432441aecdSOmair Javaid if (error.Fail()) 9442441aecdSOmair Javaid return error; 9452441aecdSOmair Javaid 9462441aecdSOmair Javaid m_max_hwp_supported = (cap_val >> 8) & 0xff; 9472441aecdSOmair Javaid m_max_hbp_supported = cap_val & 0xff; 9482441aecdSOmair Javaid m_refresh_hwdebug_info = false; 9492441aecdSOmair Javaid 9502441aecdSOmair Javaid return error; 9512441aecdSOmair Javaid } 9522441aecdSOmair Javaid 9532441aecdSOmair Javaid Error 9542441aecdSOmair Javaid NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, int hwb_index) 9552441aecdSOmair Javaid { 9562441aecdSOmair Javaid Error error; 9572441aecdSOmair Javaid 9582441aecdSOmair Javaid lldb::addr_t *addr_buf; 9592441aecdSOmair Javaid uint32_t *ctrl_buf; 9602441aecdSOmair Javaid 9612441aecdSOmair Javaid if (hwbType == eDREGTypeWATCH) 9622441aecdSOmair Javaid { 9632441aecdSOmair Javaid addr_buf = &m_hwp_regs[hwb_index].address; 9642441aecdSOmair Javaid ctrl_buf = &m_hwp_regs[hwb_index].control; 9652441aecdSOmair Javaid 9662441aecdSOmair Javaid error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, 967e85e6021STamas Berghammer m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) -((hwb_index << 1) + 1), 9682441aecdSOmair Javaid addr_buf, sizeof(unsigned int)); 9692441aecdSOmair Javaid 9702441aecdSOmair Javaid if (error.Fail()) 9712441aecdSOmair Javaid return error; 9722441aecdSOmair Javaid 9732441aecdSOmair Javaid error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, 974e85e6021STamas Berghammer m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) -((hwb_index << 1) + 2), 9752441aecdSOmair Javaid ctrl_buf, sizeof(unsigned int)); 9762441aecdSOmair Javaid } 9772441aecdSOmair Javaid else 9782441aecdSOmair Javaid { 9792441aecdSOmair Javaid addr_buf = &m_hwp_regs[hwb_index].address; 9802441aecdSOmair Javaid ctrl_buf = &m_hwp_regs[hwb_index].control; 9812441aecdSOmair Javaid 9822441aecdSOmair Javaid error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, 983e85e6021STamas Berghammer m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) ((hwb_index << 1) + 1), 9842441aecdSOmair Javaid addr_buf, sizeof(unsigned int)); 9852441aecdSOmair Javaid 9862441aecdSOmair Javaid if (error.Fail()) 9872441aecdSOmair Javaid return error; 9882441aecdSOmair Javaid 9892441aecdSOmair Javaid error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS, 990e85e6021STamas Berghammer m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) ((hwb_index << 1) + 2), 9912441aecdSOmair Javaid ctrl_buf, sizeof(unsigned int)); 9922441aecdSOmair Javaid 9932441aecdSOmair Javaid } 9942441aecdSOmair Javaid 9952441aecdSOmair Javaid return error; 9962441aecdSOmair Javaid } 997c40e7b17STamas Berghammer 998c40e7b17STamas Berghammer uint32_t 999c40e7b17STamas Berghammer NativeRegisterContextLinux_arm::CalculateFprOffset(const RegisterInfo* reg_info) const 1000c40e7b17STamas Berghammer { 1001c40e7b17STamas Berghammer return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; 1002c40e7b17STamas Berghammer } 1003c40e7b17STamas Berghammer 1004ce26b7a6STamas Berghammer Error 1005e85e6021STamas Berghammer NativeRegisterContextLinux_arm::DoReadRegisterValue(uint32_t offset, 1006e85e6021STamas Berghammer const char* reg_name, 1007e85e6021STamas Berghammer uint32_t size, 1008e85e6021STamas Berghammer RegisterValue &value) 1009e85e6021STamas Berghammer { 1010e85e6021STamas Berghammer // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android devices (always return 1011e85e6021STamas Berghammer // "Bad address"). To avoid using PTRACE_PEEKUSER we read out the full GPR register set instead. 1012e85e6021STamas Berghammer // This approach is about 4 times slower but the performance overhead is negligible in 1013e85e6021STamas Berghammer // comparision to processing time in lldb-server. 1014e85e6021STamas Berghammer assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); 1015e85e6021STamas Berghammer if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) 1016e85e6021STamas Berghammer return Error("Register isn't fit into the size of the GPR area"); 1017e85e6021STamas Berghammer 1018e85e6021STamas Berghammer Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm)); 1019e85e6021STamas Berghammer if (error.Fail()) 1020e85e6021STamas Berghammer return error; 1021e85e6021STamas Berghammer 1022e85e6021STamas Berghammer value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]); 1023e85e6021STamas Berghammer return Error(); 1024e85e6021STamas Berghammer } 1025e85e6021STamas Berghammer 1026e85e6021STamas Berghammer Error 1027ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoWriteRegisterValue(uint32_t offset, 1028ce26b7a6STamas Berghammer const char* reg_name, 1029ce26b7a6STamas Berghammer const RegisterValue &value) 1030ce26b7a6STamas Berghammer { 1031e85e6021STamas Berghammer // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android devices (always return 1032ce26b7a6STamas Berghammer // "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR register set, modify 1033ce26b7a6STamas Berghammer // the requested register and write it back. This approach is about 4 times slower but the 1034ce26b7a6STamas Berghammer // performance overhead is negligible in comparision to processing time in lldb-server. 1035ce26b7a6STamas Berghammer assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); 1036ce26b7a6STamas Berghammer if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) 1037ce26b7a6STamas Berghammer return Error("Register isn't fit into the size of the GPR area"); 1038ce26b7a6STamas Berghammer 1039ce26b7a6STamas Berghammer Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm)); 1040ce26b7a6STamas Berghammer if (error.Fail()) 1041ce26b7a6STamas Berghammer return error; 1042ce26b7a6STamas Berghammer 1043a7d7f7cfSOmair Javaid uint32_t reg_value = value.GetAsUInt32(); 1044a7d7f7cfSOmair Javaid // As precaution for an undefined behavior encountered while setting PC we 1045a7d7f7cfSOmair Javaid // will clear thumb bit of new PC if we are already in thumb mode; that is 1046a7d7f7cfSOmair Javaid // CPSR thumb mode bit is set. 1047a7d7f7cfSOmair Javaid if (offset / sizeof(uint32_t) == gpr_pc_arm) 1048a7d7f7cfSOmair Javaid { 1049a7d7f7cfSOmair Javaid // Check if we are already in thumb mode and 1050a7d7f7cfSOmair Javaid // thumb bit of current PC is read out to be zero and 1051a7d7f7cfSOmair Javaid // thumb bit of next PC is read out to be one. 1052a7d7f7cfSOmair Javaid if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && 1053a7d7f7cfSOmair Javaid !(m_gpr_arm[gpr_pc_arm] & 0x01) && 1054a7d7f7cfSOmair Javaid (value.GetAsUInt32() & 0x01)) 1055a7d7f7cfSOmair Javaid { 1056a7d7f7cfSOmair Javaid reg_value &= (~1ull); 1057a7d7f7cfSOmair Javaid } 1058a7d7f7cfSOmair Javaid } 1059a7d7f7cfSOmair Javaid 1060a7d7f7cfSOmair Javaid m_gpr_arm[offset / sizeof(uint32_t)] = reg_value; 1061ce26b7a6STamas Berghammer return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm)); 1062ce26b7a6STamas Berghammer } 1063ce26b7a6STamas Berghammer 1064ce26b7a6STamas Berghammer Error 1065e85e6021STamas Berghammer NativeRegisterContextLinux_arm::DoReadGPR(void *buf, size_t buf_size) 1066e85e6021STamas Berghammer { 1067e85e6021STamas Berghammer #ifdef __arm__ 1068e85e6021STamas Berghammer return NativeRegisterContextLinux::DoReadGPR(buf, buf_size); 1069e85e6021STamas Berghammer #else // __aarch64__ 1070e85e6021STamas Berghammer struct iovec ioVec; 1071e85e6021STamas Berghammer ioVec.iov_base = buf; 1072e85e6021STamas Berghammer ioVec.iov_len = buf_size; 1073e85e6021STamas Berghammer 1074e85e6021STamas Berghammer return ReadRegisterSet(&ioVec, buf_size, NT_PRSTATUS); 1075e85e6021STamas Berghammer #endif // __arm__ 1076e85e6021STamas Berghammer } 1077e85e6021STamas Berghammer 1078e85e6021STamas Berghammer Error 1079e85e6021STamas Berghammer NativeRegisterContextLinux_arm::DoWriteGPR(void *buf, size_t buf_size) 1080e85e6021STamas Berghammer { 1081e85e6021STamas Berghammer #ifdef __arm__ 1082e85e6021STamas Berghammer return NativeRegisterContextLinux::DoWriteGPR(buf, buf_size); 1083e85e6021STamas Berghammer #else // __aarch64__ 1084e85e6021STamas Berghammer struct iovec ioVec; 1085e85e6021STamas Berghammer ioVec.iov_base = buf; 1086e85e6021STamas Berghammer ioVec.iov_len = buf_size; 1087e85e6021STamas Berghammer 1088e85e6021STamas Berghammer return WriteRegisterSet(&ioVec, buf_size, NT_PRSTATUS); 1089e85e6021STamas Berghammer #endif // __arm__ 1090e85e6021STamas Berghammer } 1091e85e6021STamas Berghammer 1092e85e6021STamas Berghammer Error 1093ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size) 1094ce26b7a6STamas Berghammer { 1095e85e6021STamas Berghammer #ifdef __arm__ 1096ce26b7a6STamas Berghammer return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, 1097ce26b7a6STamas Berghammer m_thread.GetID(), 1098ce26b7a6STamas Berghammer nullptr, 1099ce26b7a6STamas Berghammer buf, 1100ce26b7a6STamas Berghammer buf_size); 1101e85e6021STamas Berghammer #else // __aarch64__ 1102e85e6021STamas Berghammer struct iovec ioVec; 1103e85e6021STamas Berghammer ioVec.iov_base = buf; 1104e85e6021STamas Berghammer ioVec.iov_len = buf_size; 1105e85e6021STamas Berghammer 1106e85e6021STamas Berghammer return ReadRegisterSet(&ioVec, buf_size, NT_ARM_VFP); 1107e85e6021STamas Berghammer #endif // __arm__ 1108ce26b7a6STamas Berghammer } 1109ce26b7a6STamas Berghammer 1110ce26b7a6STamas Berghammer Error 1111ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size) 1112ce26b7a6STamas Berghammer { 1113e85e6021STamas Berghammer #ifdef __arm__ 1114ce26b7a6STamas Berghammer return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, 1115ce26b7a6STamas Berghammer m_thread.GetID(), 1116ce26b7a6STamas Berghammer nullptr, 1117ce26b7a6STamas Berghammer buf, 1118ce26b7a6STamas Berghammer buf_size); 1119e85e6021STamas Berghammer #else // __aarch64__ 1120e85e6021STamas Berghammer struct iovec ioVec; 1121e85e6021STamas Berghammer ioVec.iov_base = buf; 1122e85e6021STamas Berghammer ioVec.iov_len = buf_size; 1123e85e6021STamas Berghammer 1124e85e6021STamas Berghammer return WriteRegisterSet(&ioVec, buf_size, NT_ARM_VFP); 1125e85e6021STamas Berghammer #endif // __arm__ 1126ce26b7a6STamas Berghammer } 1127ce26b7a6STamas Berghammer 1128e85e6021STamas Berghammer #endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 1129