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 &reg_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 &reg_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