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 
10068f8a7eSTamas Berghammer #if defined(__arm__)
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 
19068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
203f57216cSOmair Javaid 
213f57216cSOmair Javaid #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr))
223f57216cSOmair Javaid 
23ce26b7a6STamas Berghammer #ifndef PTRACE_GETVFPREGS
24ce26b7a6STamas Berghammer   #define PTRACE_GETVFPREGS 27
25ce26b7a6STamas Berghammer   #define PTRACE_SETVFPREGS 28
26ce26b7a6STamas Berghammer #endif
272441aecdSOmair Javaid #ifndef PTRACE_GETHBPREGS
282441aecdSOmair Javaid   #define PTRACE_GETHBPREGS 29
292441aecdSOmair Javaid   #define PTRACE_SETHBPREGS 30
302441aecdSOmair Javaid #endif
312441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG3)
322441aecdSOmair Javaid   #define PTRACE_TYPE_ARG3 void *
332441aecdSOmair Javaid #endif
342441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG4)
352441aecdSOmair Javaid   #define PTRACE_TYPE_ARG4 void *
362441aecdSOmair Javaid #endif
372441aecdSOmair Javaid 
383f57216cSOmair Javaid using namespace lldb;
393f57216cSOmair Javaid using namespace lldb_private;
403f57216cSOmair Javaid using namespace lldb_private::process_linux;
413f57216cSOmair Javaid 
423f57216cSOmair Javaid // arm general purpose registers.
433f57216cSOmair Javaid static const uint32_t g_gpr_regnums_arm[] =
443f57216cSOmair Javaid {
453f57216cSOmair Javaid     gpr_r0_arm,
463f57216cSOmair Javaid     gpr_r1_arm,
473f57216cSOmair Javaid     gpr_r2_arm,
483f57216cSOmair Javaid     gpr_r3_arm,
493f57216cSOmair Javaid     gpr_r4_arm,
503f57216cSOmair Javaid     gpr_r5_arm,
513f57216cSOmair Javaid     gpr_r6_arm,
523f57216cSOmair Javaid     gpr_r7_arm,
533f57216cSOmair Javaid     gpr_r8_arm,
543f57216cSOmair Javaid     gpr_r9_arm,
553f57216cSOmair Javaid     gpr_r10_arm,
563f57216cSOmair Javaid     gpr_r11_arm,
573f57216cSOmair Javaid     gpr_r12_arm,
583f57216cSOmair Javaid     gpr_sp_arm,
593f57216cSOmair Javaid     gpr_lr_arm,
603f57216cSOmair Javaid     gpr_pc_arm,
613f57216cSOmair Javaid     gpr_cpsr_arm,
623f57216cSOmair Javaid     LLDB_INVALID_REGNUM // register sets need to end with this flag
633f57216cSOmair Javaid };
643f57216cSOmair Javaid static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == k_num_gpr_registers_arm, \
653f57216cSOmair Javaid               "g_gpr_regnums_arm has wrong number of register infos");
663f57216cSOmair Javaid 
673f57216cSOmair Javaid // arm floating point registers.
683f57216cSOmair Javaid static const uint32_t g_fpu_regnums_arm[] =
693f57216cSOmair Javaid {
703f57216cSOmair Javaid     fpu_s0_arm,
713f57216cSOmair Javaid     fpu_s1_arm,
723f57216cSOmair Javaid     fpu_s2_arm,
733f57216cSOmair Javaid     fpu_s3_arm,
743f57216cSOmair Javaid     fpu_s4_arm,
753f57216cSOmair Javaid     fpu_s5_arm,
763f57216cSOmair Javaid     fpu_s6_arm,
773f57216cSOmair Javaid     fpu_s7_arm,
783f57216cSOmair Javaid     fpu_s8_arm,
793f57216cSOmair Javaid     fpu_s9_arm,
803f57216cSOmair Javaid     fpu_s10_arm,
813f57216cSOmair Javaid     fpu_s11_arm,
823f57216cSOmair Javaid     fpu_s12_arm,
833f57216cSOmair Javaid     fpu_s13_arm,
843f57216cSOmair Javaid     fpu_s14_arm,
853f57216cSOmair Javaid     fpu_s15_arm,
863f57216cSOmair Javaid     fpu_s16_arm,
873f57216cSOmair Javaid     fpu_s17_arm,
883f57216cSOmair Javaid     fpu_s18_arm,
893f57216cSOmair Javaid     fpu_s19_arm,
903f57216cSOmair Javaid     fpu_s20_arm,
913f57216cSOmair Javaid     fpu_s21_arm,
923f57216cSOmair Javaid     fpu_s22_arm,
933f57216cSOmair Javaid     fpu_s23_arm,
943f57216cSOmair Javaid     fpu_s24_arm,
953f57216cSOmair Javaid     fpu_s25_arm,
963f57216cSOmair Javaid     fpu_s26_arm,
973f57216cSOmair Javaid     fpu_s27_arm,
983f57216cSOmair Javaid     fpu_s28_arm,
993f57216cSOmair Javaid     fpu_s29_arm,
1003f57216cSOmair Javaid     fpu_s30_arm,
1013f57216cSOmair Javaid     fpu_s31_arm,
1023f57216cSOmair Javaid     fpu_fpscr_arm,
1033f57216cSOmair Javaid     LLDB_INVALID_REGNUM // register sets need to end with this flag
1043f57216cSOmair Javaid };
1053f57216cSOmair Javaid static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \
1063f57216cSOmair Javaid               "g_fpu_regnums_arm has wrong number of register infos");
1073f57216cSOmair Javaid 
1083f57216cSOmair Javaid namespace {
1093f57216cSOmair Javaid     // Number of register sets provided by this context.
1103f57216cSOmair Javaid     enum
1113f57216cSOmair Javaid     {
1123f57216cSOmair Javaid         k_num_register_sets = 2
1133f57216cSOmair Javaid     };
1143f57216cSOmair Javaid }
1153f57216cSOmair Javaid 
1163f57216cSOmair Javaid // Register sets for arm.
1173f57216cSOmair Javaid static const RegisterSet
1183f57216cSOmair Javaid g_reg_sets_arm[k_num_register_sets] =
1193f57216cSOmair Javaid {
1203f57216cSOmair Javaid     { "General Purpose Registers",  "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm },
1213f57216cSOmair Javaid     { "Floating Point Registers",   "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm }
1223f57216cSOmair Javaid };
1233f57216cSOmair Javaid 
124068f8a7eSTamas Berghammer NativeRegisterContextLinux*
125068f8a7eSTamas Berghammer NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
1263f57216cSOmair Javaid                                                                  NativeThreadProtocol &native_thread,
127068f8a7eSTamas Berghammer                                                                  uint32_t concrete_frame_idx)
1283f57216cSOmair Javaid {
129068f8a7eSTamas Berghammer     return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx);
130068f8a7eSTamas Berghammer }
131068f8a7eSTamas Berghammer 
132068f8a7eSTamas Berghammer NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm (const ArchSpec& target_arch,
133068f8a7eSTamas Berghammer                                                                 NativeThreadProtocol &native_thread,
134068f8a7eSTamas Berghammer                                                                 uint32_t concrete_frame_idx) :
135068f8a7eSTamas Berghammer     NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm(target_arch))
136068f8a7eSTamas Berghammer {
137068f8a7eSTamas Berghammer     switch (target_arch.GetMachine())
1383f57216cSOmair Javaid     {
1393f57216cSOmair Javaid         case llvm::Triple::arm:
1403f57216cSOmair Javaid             m_reg_info.num_registers     = k_num_registers_arm;
1413f57216cSOmair Javaid             m_reg_info.num_gpr_registers = k_num_gpr_registers_arm;
1423f57216cSOmair Javaid             m_reg_info.num_fpr_registers = k_num_fpr_registers_arm;
1433f57216cSOmair Javaid             m_reg_info.last_gpr          = k_last_gpr_arm;
1443f57216cSOmair Javaid             m_reg_info.first_fpr         = k_first_fpr_arm;
1453f57216cSOmair Javaid             m_reg_info.last_fpr          = k_last_fpr_arm;
1463f57216cSOmair Javaid             m_reg_info.first_fpr_v       = fpu_s0_arm;
1473f57216cSOmair Javaid             m_reg_info.last_fpr_v        = fpu_s31_arm;
1483f57216cSOmair Javaid             m_reg_info.gpr_flags         = gpr_cpsr_arm;
1493f57216cSOmair Javaid             break;
1503f57216cSOmair Javaid         default:
1513f57216cSOmair Javaid             assert(false && "Unhandled target architecture.");
1523f57216cSOmair Javaid             break;
1533f57216cSOmair Javaid     }
1543f57216cSOmair Javaid 
1553f57216cSOmair Javaid     ::memset(&m_fpr, 0, sizeof (m_fpr));
1563f57216cSOmair Javaid     ::memset(&m_gpr_arm, 0, sizeof (m_gpr_arm));
1572441aecdSOmair Javaid     ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs));
1582441aecdSOmair Javaid 
1592441aecdSOmair Javaid     // 16 is just a maximum value, query hardware for actual watchpoint count
1602441aecdSOmair Javaid     m_max_hwp_supported = 16;
1612441aecdSOmair Javaid     m_max_hbp_supported = 16;
1622441aecdSOmair Javaid     m_refresh_hwdebug_info = true;
1633f57216cSOmair Javaid }
1643f57216cSOmair Javaid 
1653f57216cSOmair Javaid uint32_t
1663f57216cSOmair Javaid NativeRegisterContextLinux_arm::GetRegisterSetCount () const
1673f57216cSOmair Javaid {
1683f57216cSOmair Javaid     return k_num_register_sets;
1693f57216cSOmair Javaid }
1703f57216cSOmair Javaid 
1711f149204STamas Berghammer uint32_t
1721f149204STamas Berghammer NativeRegisterContextLinux_arm::GetUserRegisterCount() const
1731f149204STamas Berghammer {
1741f149204STamas Berghammer     uint32_t count = 0;
1751f149204STamas Berghammer     for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
1761f149204STamas Berghammer         count += g_reg_sets_arm[set_index].num_registers;
1771f149204STamas Berghammer     return count;
1781f149204STamas Berghammer }
1791f149204STamas Berghammer 
1803f57216cSOmair Javaid const RegisterSet *
1813f57216cSOmair Javaid NativeRegisterContextLinux_arm::GetRegisterSet (uint32_t set_index) const
1823f57216cSOmair Javaid {
1833f57216cSOmair Javaid     if (set_index < k_num_register_sets)
1843f57216cSOmair Javaid         return &g_reg_sets_arm[set_index];
1853f57216cSOmair Javaid 
1863f57216cSOmair Javaid     return nullptr;
1873f57216cSOmair Javaid }
1883f57216cSOmair Javaid 
1893f57216cSOmair Javaid Error
1903f57216cSOmair Javaid NativeRegisterContextLinux_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
1913f57216cSOmair Javaid {
1923f57216cSOmair Javaid     Error error;
1933f57216cSOmair Javaid 
1943f57216cSOmair Javaid     if (!reg_info)
1953f57216cSOmair Javaid     {
1963f57216cSOmair Javaid         error.SetErrorString ("reg_info NULL");
1973f57216cSOmair Javaid         return error;
1983f57216cSOmair Javaid     }
1993f57216cSOmair Javaid 
2003f57216cSOmair Javaid     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
2013f57216cSOmair Javaid 
2023f57216cSOmair Javaid     if (IsFPR(reg))
2033f57216cSOmair Javaid     {
204068f8a7eSTamas Berghammer         error = ReadFPR();
205068f8a7eSTamas Berghammer         if (error.Fail())
2063f57216cSOmair Javaid             return error;
2073f57216cSOmair Javaid     }
2083f57216cSOmair Javaid     else
2093f57216cSOmair Javaid     {
2103f57216cSOmair Javaid         uint32_t full_reg = reg;
2113f57216cSOmair Javaid         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
2123f57216cSOmair Javaid 
2133f57216cSOmair Javaid         if (is_subreg)
2143f57216cSOmair Javaid         {
2153f57216cSOmair Javaid             // Read the full aligned 64-bit register.
2163f57216cSOmair Javaid             full_reg = reg_info->invalidate_regs[0];
2173f57216cSOmair Javaid         }
2183f57216cSOmair Javaid 
2193f57216cSOmair Javaid         error = ReadRegisterRaw(full_reg, reg_value);
2203f57216cSOmair Javaid 
2213f57216cSOmair Javaid         if (error.Success ())
2223f57216cSOmair Javaid         {
2233f57216cSOmair Javaid             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
2243f57216cSOmair Javaid             if (is_subreg && (reg_info->byte_offset & 0x1))
2253f57216cSOmair Javaid                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
2263f57216cSOmair Javaid 
2273f57216cSOmair Javaid             // If our return byte size was greater than the return value reg size, then
2283f57216cSOmair Javaid             // use the type specified by reg_info rather than the uint64_t default
2293f57216cSOmair Javaid             if (reg_value.GetByteSize() > reg_info->byte_size)
2303f57216cSOmair Javaid                 reg_value.SetType(reg_info);
2313f57216cSOmair Javaid         }
2323f57216cSOmair Javaid         return error;
2333f57216cSOmair Javaid     }
2343f57216cSOmair Javaid 
2353f57216cSOmair Javaid     // Get pointer to m_fpr variable and set the data from it.
236c40e7b17STamas Berghammer     uint32_t fpr_offset = CalculateFprOffset(reg_info);
237c40e7b17STamas Berghammer     assert (fpr_offset < sizeof m_fpr);
238c40e7b17STamas Berghammer     uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
2393f57216cSOmair Javaid     switch (reg_info->byte_size)
2403f57216cSOmair Javaid     {
2413f57216cSOmair Javaid         case 2:
2423f57216cSOmair Javaid             reg_value.SetUInt16(*(uint16_t *)src);
2433f57216cSOmair Javaid             break;
2443f57216cSOmair Javaid         case 4:
2453f57216cSOmair Javaid             reg_value.SetUInt32(*(uint32_t *)src);
2463f57216cSOmair Javaid             break;
2473f57216cSOmair Javaid         case 8:
2483f57216cSOmair Javaid             reg_value.SetUInt64(*(uint64_t *)src);
2493f57216cSOmair Javaid             break;
2503f57216cSOmair Javaid         default:
2513f57216cSOmair Javaid             assert(false && "Unhandled data size.");
2523f57216cSOmair Javaid             error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
2533f57216cSOmair Javaid             break;
2543f57216cSOmair Javaid     }
2553f57216cSOmair Javaid 
2563f57216cSOmair Javaid     return error;
2573f57216cSOmair Javaid }
2583f57216cSOmair Javaid 
2593f57216cSOmair Javaid Error
2603f57216cSOmair Javaid NativeRegisterContextLinux_arm::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
2613f57216cSOmair Javaid {
2623f57216cSOmair Javaid     if (!reg_info)
2633f57216cSOmair Javaid         return Error ("reg_info NULL");
2643f57216cSOmair Javaid 
2653f57216cSOmair Javaid     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
2663f57216cSOmair Javaid     if (reg_index == LLDB_INVALID_REGNUM)
2673f57216cSOmair Javaid         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
2683f57216cSOmair Javaid 
2693f57216cSOmair Javaid     if (IsGPR(reg_index))
2703f57216cSOmair Javaid         return WriteRegisterRaw(reg_index, reg_value);
2713f57216cSOmair Javaid 
2723f57216cSOmair Javaid     if (IsFPR(reg_index))
2733f57216cSOmair Javaid     {
2743f57216cSOmair Javaid         // Get pointer to m_fpr variable and set the data to it.
275c40e7b17STamas Berghammer         uint32_t fpr_offset = CalculateFprOffset(reg_info);
276c40e7b17STamas Berghammer         assert (fpr_offset < sizeof m_fpr);
277c40e7b17STamas Berghammer         uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
2783f57216cSOmair Javaid         switch (reg_info->byte_size)
2793f57216cSOmair Javaid         {
2803f57216cSOmair Javaid             case 2:
2813f57216cSOmair Javaid                 *(uint16_t *)dst = reg_value.GetAsUInt16();
2823f57216cSOmair Javaid                 break;
2833f57216cSOmair Javaid             case 4:
2843f57216cSOmair Javaid                 *(uint32_t *)dst = reg_value.GetAsUInt32();
2853f57216cSOmair Javaid                 break;
2863f57216cSOmair Javaid             case 8:
2873f57216cSOmair Javaid                 *(uint64_t *)dst = reg_value.GetAsUInt64();
2883f57216cSOmair Javaid                 break;
2893f57216cSOmair Javaid             default:
2903f57216cSOmair Javaid                 assert(false && "Unhandled data size.");
2913f57216cSOmair Javaid                 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
2923f57216cSOmair Javaid         }
2933f57216cSOmair Javaid 
294068f8a7eSTamas Berghammer         Error error = WriteFPR();
295068f8a7eSTamas Berghammer         if (error.Fail())
296068f8a7eSTamas Berghammer             return error;
2973f57216cSOmair Javaid 
2983f57216cSOmair Javaid         return Error ();
2993f57216cSOmair Javaid     }
3003f57216cSOmair Javaid 
3013f57216cSOmair Javaid     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
3023f57216cSOmair Javaid }
3033f57216cSOmair Javaid 
3043f57216cSOmair Javaid Error
3053f57216cSOmair Javaid NativeRegisterContextLinux_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
3063f57216cSOmair Javaid {
3073f57216cSOmair Javaid     Error error;
3083f57216cSOmair Javaid 
3093f57216cSOmair Javaid     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
3103f57216cSOmair Javaid     if (!data_sp)
311bef47e49SGreg Clayton         return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, (uint64_t)REG_CONTEXT_SIZE);
3123f57216cSOmair Javaid 
313068f8a7eSTamas Berghammer     error = ReadGPR();
314068f8a7eSTamas Berghammer     if (error.Fail())
3153f57216cSOmair Javaid         return error;
3163f57216cSOmair Javaid 
317068f8a7eSTamas Berghammer     error = ReadFPR();
318068f8a7eSTamas Berghammer     if (error.Fail())
3193f57216cSOmair Javaid         return error;
3203f57216cSOmair Javaid 
3213f57216cSOmair Javaid     uint8_t *dst = data_sp->GetBytes ();
3223f57216cSOmair Javaid     if (dst == nullptr)
3233f57216cSOmair Javaid     {
324bef47e49SGreg Clayton         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", (uint64_t)REG_CONTEXT_SIZE);
3253f57216cSOmair Javaid         return error;
3263f57216cSOmair Javaid     }
3273f57216cSOmair Javaid 
3283f57216cSOmair Javaid     ::memcpy (dst, &m_gpr_arm, GetGPRSize());
3293f57216cSOmair Javaid     dst += GetGPRSize();
3303f57216cSOmair Javaid     ::memcpy (dst, &m_fpr, sizeof(m_fpr));
3313f57216cSOmair Javaid 
3323f57216cSOmair Javaid     return error;
3333f57216cSOmair Javaid }
3343f57216cSOmair Javaid 
3353f57216cSOmair Javaid Error
3363f57216cSOmair Javaid NativeRegisterContextLinux_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
3373f57216cSOmair Javaid {
3383f57216cSOmair Javaid     Error error;
3393f57216cSOmair Javaid 
3403f57216cSOmair Javaid     if (!data_sp)
3413f57216cSOmair Javaid     {
3423f57216cSOmair Javaid         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
3433f57216cSOmair Javaid         return error;
3443f57216cSOmair Javaid     }
3453f57216cSOmair Javaid 
3463f57216cSOmair Javaid     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
3473f57216cSOmair Javaid     {
348bef47e49SGreg 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 ());
3493f57216cSOmair Javaid         return error;
3503f57216cSOmair Javaid     }
3513f57216cSOmair Javaid 
3523f57216cSOmair Javaid 
3533f57216cSOmair Javaid     uint8_t *src = data_sp->GetBytes ();
3543f57216cSOmair Javaid     if (src == nullptr)
3553f57216cSOmair Javaid     {
3563f57216cSOmair Javaid         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
3573f57216cSOmair Javaid         return error;
3583f57216cSOmair Javaid     }
3593f57216cSOmair Javaid     ::memcpy (&m_gpr_arm, src, GetRegisterInfoInterface ().GetGPRSize ());
3603f57216cSOmair Javaid 
361068f8a7eSTamas Berghammer     error = WriteGPR();
362068f8a7eSTamas Berghammer     if (error.Fail())
3633f57216cSOmair Javaid         return error;
3643f57216cSOmair Javaid 
3653f57216cSOmair Javaid     src += GetRegisterInfoInterface ().GetGPRSize ();
3663f57216cSOmair Javaid     ::memcpy (&m_fpr, src, sizeof(m_fpr));
3673f57216cSOmair Javaid 
368068f8a7eSTamas Berghammer     error = WriteFPR();
3693f57216cSOmair Javaid     if (error.Fail())
3703f57216cSOmair Javaid         return error;
3713f57216cSOmair Javaid 
3723f57216cSOmair Javaid     return error;
3733f57216cSOmair Javaid }
3743f57216cSOmair Javaid 
3753f57216cSOmair Javaid bool
3763f57216cSOmair Javaid NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const
3773f57216cSOmair Javaid {
3783f57216cSOmair Javaid     return reg <= m_reg_info.last_gpr;   // GPR's come first.
3793f57216cSOmair Javaid }
3803f57216cSOmair Javaid 
3813f57216cSOmair Javaid bool
3823f57216cSOmair Javaid NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const
3833f57216cSOmair Javaid {
3843f57216cSOmair Javaid     return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
3853f57216cSOmair Javaid }
3863f57216cSOmair Javaid 
3872441aecdSOmair Javaid uint32_t
3882441aecdSOmair Javaid NativeRegisterContextLinux_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
3892441aecdSOmair Javaid {
3902441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
3912441aecdSOmair Javaid 
3922441aecdSOmair Javaid     if (log)
3932441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
3942441aecdSOmair Javaid 
3952441aecdSOmair Javaid     Error error;
3962441aecdSOmair Javaid 
3972441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
3982441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
3992441aecdSOmair Javaid 
4002441aecdSOmair Javaid     if (error.Fail())
4012441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
4022441aecdSOmair Javaid 
4032441aecdSOmair Javaid     uint32_t control_value = 0, bp_index = 0;
4042441aecdSOmair Javaid 
4052441aecdSOmair Javaid     // Check if size has a valid hardware breakpoint length.
4062441aecdSOmair Javaid     // Thumb instructions are 2-bytes but we have no way here to determine
4072441aecdSOmair Javaid     // if target address is a thumb or arm instruction.
4082441aecdSOmair Javaid     // TODO: Add support for setting thumb mode hardware breakpoints
4092441aecdSOmair Javaid     if (size != 4 && size != 2)
4102441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
4112441aecdSOmair Javaid 
4122441aecdSOmair Javaid     // Setup control value
4132441aecdSOmair Javaid     // Make the byte_mask into a valid Byte Address Select mask
4142441aecdSOmair Javaid     control_value = 0xfu << 5;
4152441aecdSOmair Javaid 
4162441aecdSOmair Javaid     // Enable this breakpoint and make it stop in privileged or user mode;
4172441aecdSOmair Javaid     control_value |= 7;
4182441aecdSOmair Javaid 
4192441aecdSOmair Javaid     // Make sure bits 1:0 are clear in our address
4202441aecdSOmair Javaid     // This should be different once we support thumb here.
4212441aecdSOmair Javaid     addr &= ~((lldb::addr_t)3);
4222441aecdSOmair Javaid 
4232441aecdSOmair Javaid     // Iterate over stored hardware breakpoints
4242441aecdSOmair Javaid     // Find a free bp_index or update reference count if duplicate.
4252441aecdSOmair Javaid     bp_index = LLDB_INVALID_INDEX32;
4262441aecdSOmair Javaid 
4272441aecdSOmair Javaid     for (uint32_t i = 0; i < m_max_hbp_supported; i++)
4282441aecdSOmair Javaid     {
4292441aecdSOmair Javaid         if ((m_hbr_regs[i].control & 1) == 0)
4302441aecdSOmair Javaid         {
4312441aecdSOmair Javaid             bp_index = i;  // Mark last free slot
4322441aecdSOmair Javaid         }
4332441aecdSOmair Javaid         else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
4342441aecdSOmair Javaid         {
4352441aecdSOmair Javaid             bp_index = i;  // Mark duplicate index
4362441aecdSOmair Javaid             break;  // Stop searching here
4372441aecdSOmair Javaid         }
4382441aecdSOmair Javaid     }
4392441aecdSOmair Javaid 
4402441aecdSOmair Javaid      if (bp_index == LLDB_INVALID_INDEX32)
4412441aecdSOmair Javaid          return LLDB_INVALID_INDEX32;
4422441aecdSOmair Javaid 
443*4aa984c1SOmair Javaid     // Add new or update existing breakpoint
4442441aecdSOmair Javaid     if ((m_hbr_regs[bp_index].control & 1) == 0)
4452441aecdSOmair Javaid     {
4462441aecdSOmair Javaid         m_hbr_regs[bp_index].address = addr;
4472441aecdSOmair Javaid         m_hbr_regs[bp_index].control = control_value;
4482441aecdSOmair Javaid         m_hbr_regs[bp_index].refcount = 1;
4492441aecdSOmair Javaid 
4502441aecdSOmair Javaid         // PTRACE call to set corresponding hardware breakpoint register.
4512441aecdSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
4522441aecdSOmair Javaid 
4532441aecdSOmair Javaid         if (error.Fail())
4542441aecdSOmair Javaid             return LLDB_INVALID_INDEX32;
4552441aecdSOmair Javaid     }
4562441aecdSOmair Javaid     else
4572441aecdSOmair Javaid         m_hbr_regs[bp_index].refcount++;
4582441aecdSOmair Javaid 
4592441aecdSOmair Javaid     return bp_index;
4602441aecdSOmair Javaid }
4612441aecdSOmair Javaid 
4622441aecdSOmair Javaid bool
4632441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearHardwareBreakpoint (uint32_t hw_idx)
4642441aecdSOmair Javaid {
4652441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
4662441aecdSOmair Javaid 
4672441aecdSOmair Javaid     if (log)
4682441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
4692441aecdSOmair Javaid 
4702441aecdSOmair Javaid     Error error;
4712441aecdSOmair Javaid 
4722441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
4732441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
4742441aecdSOmair Javaid 
4752441aecdSOmair Javaid     if (error.Fail())
476*4aa984c1SOmair Javaid         return false;
4772441aecdSOmair Javaid 
4782441aecdSOmair Javaid     if (hw_idx >= m_max_hbp_supported)
4792441aecdSOmair Javaid         return false;
4802441aecdSOmair Javaid 
4812441aecdSOmair Javaid     // Update reference count if multiple references.
4822441aecdSOmair Javaid     if (m_hbr_regs[hw_idx].refcount > 1)
4832441aecdSOmair Javaid     {
4842441aecdSOmair Javaid         m_hbr_regs[hw_idx].refcount--;
4852441aecdSOmair Javaid         return true;
4862441aecdSOmair Javaid     }
4872441aecdSOmair Javaid     else if (m_hbr_regs[hw_idx].refcount == 1)
4882441aecdSOmair Javaid     {
4892441aecdSOmair Javaid         m_hbr_regs[hw_idx].control &= ~1;
4902441aecdSOmair Javaid         m_hbr_regs[hw_idx].address = 0;
4912441aecdSOmair Javaid         m_hbr_regs[hw_idx].refcount = 0;
4922441aecdSOmair Javaid 
4932441aecdSOmair Javaid         // PTRACE call to clear corresponding hardware breakpoint register.
4942441aecdSOmair Javaid         WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
4952441aecdSOmair Javaid 
4962441aecdSOmair Javaid         if (error.Fail())
497*4aa984c1SOmair Javaid             return false;
4982441aecdSOmair Javaid 
4992441aecdSOmair Javaid         return true;
5002441aecdSOmair Javaid     }
5012441aecdSOmair Javaid 
5022441aecdSOmair Javaid     return false;
5032441aecdSOmair Javaid }
5042441aecdSOmair Javaid 
5052441aecdSOmair Javaid uint32_t
5062441aecdSOmair Javaid NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints ()
5072441aecdSOmair Javaid {
5082441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
5092441aecdSOmair Javaid 
5102441aecdSOmair Javaid     if (log)
5112441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
5122441aecdSOmair Javaid 
5132441aecdSOmair Javaid     Error error;
5142441aecdSOmair Javaid 
5152441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
5162441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
5172441aecdSOmair Javaid 
5182441aecdSOmair Javaid     if (error.Fail())
5192441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
5202441aecdSOmair Javaid 
5212441aecdSOmair Javaid     return m_max_hwp_supported;
5222441aecdSOmair Javaid }
5232441aecdSOmair Javaid 
5242441aecdSOmair Javaid uint32_t
5252441aecdSOmair Javaid NativeRegisterContextLinux_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
5262441aecdSOmair Javaid {
5272441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
5282441aecdSOmair Javaid 
5292441aecdSOmair Javaid     if (log)
5302441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
5312441aecdSOmair Javaid 
5322441aecdSOmair Javaid     Error error;
5332441aecdSOmair Javaid 
5342441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
5352441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
5362441aecdSOmair Javaid 
5372441aecdSOmair Javaid     if (error.Fail())
5382441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
5392441aecdSOmair Javaid 
5402441aecdSOmair Javaid     uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
5412441aecdSOmair Javaid 
5422441aecdSOmair Javaid     // Check if we are setting watchpoint other than read/write/access
5432441aecdSOmair Javaid     // Also update watchpoint flag to match Arm write-read bit configuration.
5442441aecdSOmair Javaid     switch (watch_flags)
5452441aecdSOmair Javaid     {
5462441aecdSOmair Javaid         case 1:
5472441aecdSOmair Javaid             watch_flags = 2;
5482441aecdSOmair Javaid             break;
5492441aecdSOmair Javaid         case 2:
5502441aecdSOmair Javaid             watch_flags = 1;
5512441aecdSOmair Javaid             break;
5522441aecdSOmair Javaid         case 3:
5532441aecdSOmair Javaid             break;
5542441aecdSOmair Javaid         default:
5552441aecdSOmair Javaid             return LLDB_INVALID_INDEX32;
5562441aecdSOmair Javaid     }
5572441aecdSOmair Javaid 
5582441aecdSOmair Javaid     // Can't watch zero bytes
5592441aecdSOmair Javaid     // Can't watch more than 4 bytes per WVR/WCR pair
5602441aecdSOmair Javaid 
5612441aecdSOmair Javaid     if (size == 0 || size > 4)
5622441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
5632441aecdSOmair Javaid 
5642441aecdSOmair Javaid     // We can only watch up to four bytes that follow a 4 byte aligned address
5652441aecdSOmair Javaid     // per watchpoint register pair, so make sure we can properly encode this.
5662441aecdSOmair Javaid     addr_word_offset = addr % 4;
5672441aecdSOmair Javaid     byte_mask = ((1u << size) - 1u) << addr_word_offset;
5682441aecdSOmair Javaid 
5692441aecdSOmair Javaid     // Check if we need multiple watchpoint register
5702441aecdSOmair Javaid     if (byte_mask > 0xfu)
5712441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
5722441aecdSOmair Javaid 
5732441aecdSOmair Javaid     // Setup control value
5742441aecdSOmair Javaid     // Make the byte_mask into a valid Byte Address Select mask
5752441aecdSOmair Javaid     control_value = byte_mask << 5;
5762441aecdSOmair Javaid 
5772441aecdSOmair Javaid     //Turn on appropriate watchpoint flags read or write
5782441aecdSOmair Javaid     control_value |= (watch_flags << 3);
5792441aecdSOmair Javaid 
5802441aecdSOmair Javaid     // Enable this watchpoint and make it stop in privileged or user mode;
5812441aecdSOmair Javaid     control_value |= 7;
5822441aecdSOmair Javaid 
5832441aecdSOmair Javaid     // Make sure bits 1:0 are clear in our address
5842441aecdSOmair Javaid     addr &= ~((lldb::addr_t)3);
5852441aecdSOmair Javaid 
5862441aecdSOmair Javaid     // Iterate over stored watchpoints
5872441aecdSOmair Javaid     // Find a free wp_index or update reference count if duplicate.
5882441aecdSOmair Javaid     wp_index = LLDB_INVALID_INDEX32;
5892441aecdSOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
5902441aecdSOmair Javaid     {
5912441aecdSOmair Javaid         if ((m_hwp_regs[i].control & 1) == 0)
5922441aecdSOmair Javaid         {
5932441aecdSOmair Javaid             wp_index = i; // Mark last free slot
5942441aecdSOmair Javaid         }
5952441aecdSOmair Javaid         else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
5962441aecdSOmair Javaid         {
5972441aecdSOmair Javaid             wp_index = i; // Mark duplicate index
5982441aecdSOmair Javaid             break; // Stop searching here
5992441aecdSOmair Javaid         }
6002441aecdSOmair Javaid     }
6012441aecdSOmair Javaid 
6022441aecdSOmair Javaid      if (wp_index == LLDB_INVALID_INDEX32)
6032441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
6042441aecdSOmair Javaid 
6052441aecdSOmair Javaid     // Add new or update existing watchpoint
6062441aecdSOmair Javaid     if ((m_hwp_regs[wp_index].control & 1) == 0)
6072441aecdSOmair Javaid     {
6082441aecdSOmair Javaid         // Update watchpoint in local cache
6092441aecdSOmair Javaid         m_hwp_regs[wp_index].address = addr;
6102441aecdSOmair Javaid         m_hwp_regs[wp_index].control = control_value;
6112441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount = 1;
6122441aecdSOmair Javaid 
6132441aecdSOmair Javaid         // PTRACE call to set corresponding watchpoint register.
6142441aecdSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
6152441aecdSOmair Javaid 
6162441aecdSOmair Javaid         if (error.Fail())
6172441aecdSOmair Javaid             return LLDB_INVALID_INDEX32;
6182441aecdSOmair Javaid     }
6192441aecdSOmair Javaid     else
6202441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount++;
6212441aecdSOmair Javaid 
6222441aecdSOmair Javaid     return wp_index;
6232441aecdSOmair Javaid }
6242441aecdSOmair Javaid 
6252441aecdSOmair Javaid bool
6262441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearHardwareWatchpoint (uint32_t wp_index)
6272441aecdSOmair Javaid {
6282441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
6292441aecdSOmair Javaid 
6302441aecdSOmair Javaid     if (log)
6312441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
6322441aecdSOmair Javaid 
6332441aecdSOmair Javaid     Error error;
6342441aecdSOmair Javaid 
6352441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
6362441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
6372441aecdSOmair Javaid 
6382441aecdSOmair Javaid     if (error.Fail())
639*4aa984c1SOmair Javaid         return false;
6402441aecdSOmair Javaid 
6412441aecdSOmair Javaid     if (wp_index >= m_max_hwp_supported)
6422441aecdSOmair Javaid         return false;
6432441aecdSOmair Javaid 
6442441aecdSOmair Javaid     // Update reference count if multiple references.
6452441aecdSOmair Javaid     if (m_hwp_regs[wp_index].refcount > 1)
6462441aecdSOmair Javaid     {
6472441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount--;
6482441aecdSOmair Javaid         return true;
6492441aecdSOmair Javaid     }
6502441aecdSOmair Javaid     else if (m_hwp_regs[wp_index].refcount == 1)
6512441aecdSOmair Javaid     {
6522441aecdSOmair Javaid         // Update watchpoint in local cache
6532441aecdSOmair Javaid         m_hwp_regs[wp_index].control &= ~1;
6542441aecdSOmair Javaid         m_hwp_regs[wp_index].address = 0;
6552441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount = 0;
6562441aecdSOmair Javaid 
6572441aecdSOmair Javaid         // Ptrace call to update hardware debug registers
6582441aecdSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
6592441aecdSOmair Javaid 
6602441aecdSOmair Javaid         if (error.Fail())
6612441aecdSOmair Javaid             return false;
6622441aecdSOmair Javaid 
6632441aecdSOmair Javaid         return true;
6642441aecdSOmair Javaid     }
6652441aecdSOmair Javaid 
6662441aecdSOmair Javaid     return false;
6672441aecdSOmair Javaid }
6682441aecdSOmair Javaid 
6692441aecdSOmair Javaid Error
6702441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints ()
6712441aecdSOmair Javaid {
6722441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
6732441aecdSOmair Javaid 
6742441aecdSOmair Javaid     if (log)
6752441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
6762441aecdSOmair Javaid 
6772441aecdSOmair Javaid     Error error;
6782441aecdSOmair Javaid 
6792441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
6802441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
6812441aecdSOmair Javaid 
6822441aecdSOmair Javaid     if (error.Fail())
6832441aecdSOmair Javaid         return error;
6842441aecdSOmair Javaid 
6852441aecdSOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
6862441aecdSOmair Javaid     {
6872441aecdSOmair Javaid         if (m_hwp_regs[i].control & 0x01)
6882441aecdSOmair Javaid         {
6892441aecdSOmair Javaid             // Clear watchpoints in local cache
6902441aecdSOmair Javaid             m_hwp_regs[i].control &= ~1;
6912441aecdSOmair Javaid             m_hwp_regs[i].address = 0;
6922441aecdSOmair Javaid             m_hwp_regs[i].refcount = 0;
6932441aecdSOmair Javaid 
6942441aecdSOmair Javaid             // Ptrace call to update hardware debug registers
6952441aecdSOmair Javaid             error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
6962441aecdSOmair Javaid 
6972441aecdSOmair Javaid             if (error.Fail())
6982441aecdSOmair Javaid                 return error;
6992441aecdSOmair Javaid         }
7002441aecdSOmair Javaid     }
7012441aecdSOmair Javaid 
7022441aecdSOmair Javaid     return Error();
7032441aecdSOmair Javaid }
7042441aecdSOmair Javaid 
7052441aecdSOmair Javaid uint32_t
7062441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index)
7072441aecdSOmair Javaid {
7082441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
7092441aecdSOmair Javaid 
7102441aecdSOmair Javaid     if (log)
7112441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7122441aecdSOmair Javaid 
7132441aecdSOmair Javaid     switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f)
7142441aecdSOmair Javaid     {
7152441aecdSOmair Javaid         case 0x01:
7162441aecdSOmair Javaid             return 1;
7172441aecdSOmair Javaid         case 0x03:
7182441aecdSOmair Javaid             return 2;
7192441aecdSOmair Javaid         case 0x07:
7202441aecdSOmair Javaid             return 3;
7212441aecdSOmair Javaid         case 0x0f:
7222441aecdSOmair Javaid             return 4;
7232441aecdSOmair Javaid         default:
7242441aecdSOmair Javaid             return 0;
7252441aecdSOmair Javaid     }
7262441aecdSOmair Javaid }
7272441aecdSOmair Javaid bool
7282441aecdSOmair Javaid NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index)
7292441aecdSOmair Javaid {
7302441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
7312441aecdSOmair Javaid 
7322441aecdSOmair Javaid     if (log)
7332441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7342441aecdSOmair Javaid 
7352441aecdSOmair Javaid     if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
7362441aecdSOmair Javaid         return true;
7372441aecdSOmair Javaid     else
7382441aecdSOmair Javaid         return false;
7392441aecdSOmair Javaid }
7402441aecdSOmair Javaid 
7412441aecdSOmair Javaid Error
7422441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
7432441aecdSOmair Javaid {
7442441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
7452441aecdSOmair Javaid 
7462441aecdSOmair Javaid     if (log)
7472441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7482441aecdSOmair Javaid 
7492441aecdSOmair Javaid     uint32_t watch_size;
7502441aecdSOmair Javaid     lldb::addr_t watch_addr;
7512441aecdSOmair Javaid 
7522441aecdSOmair Javaid     for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
7532441aecdSOmair Javaid     {
7542441aecdSOmair Javaid         watch_size = GetWatchpointSize (wp_index);
7552441aecdSOmair Javaid         watch_addr = m_hwp_regs[wp_index].address;
7562441aecdSOmair Javaid 
7572441aecdSOmair Javaid         if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
7582441aecdSOmair Javaid             && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
7592441aecdSOmair Javaid         {
7602441aecdSOmair Javaid             return Error();
7612441aecdSOmair Javaid         }
7622441aecdSOmair Javaid     }
7632441aecdSOmair Javaid 
7642441aecdSOmair Javaid     wp_index = LLDB_INVALID_INDEX32;
7652441aecdSOmair Javaid     return Error();
7662441aecdSOmair Javaid }
7672441aecdSOmair Javaid 
7682441aecdSOmair Javaid lldb::addr_t
7692441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointAddress (uint32_t wp_index)
7702441aecdSOmair Javaid {
7712441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
7722441aecdSOmair Javaid 
7732441aecdSOmair Javaid     if (log)
7742441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7752441aecdSOmair Javaid 
7762441aecdSOmair Javaid     if (wp_index >= m_max_hwp_supported)
7772441aecdSOmair Javaid         return LLDB_INVALID_ADDRESS;
7782441aecdSOmair Javaid 
7792441aecdSOmair Javaid     if (WatchpointIsEnabled(wp_index))
7802441aecdSOmair Javaid         return m_hwp_regs[wp_index].address;
7812441aecdSOmair Javaid     else
7822441aecdSOmair Javaid         return LLDB_INVALID_ADDRESS;
7832441aecdSOmair Javaid }
7842441aecdSOmair Javaid 
7852441aecdSOmair Javaid Error
7862441aecdSOmair Javaid NativeRegisterContextLinux_arm::ReadHardwareDebugInfo()
7872441aecdSOmair Javaid {
7882441aecdSOmair Javaid     Error error;
7892441aecdSOmair Javaid 
7902441aecdSOmair Javaid     if (!m_refresh_hwdebug_info)
7912441aecdSOmair Javaid     {
7922441aecdSOmair Javaid         return Error();
7932441aecdSOmair Javaid     }
7942441aecdSOmair Javaid 
7952441aecdSOmair Javaid     unsigned int cap_val;
7962441aecdSOmair Javaid 
7972441aecdSOmair Javaid     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), nullptr, &cap_val, sizeof(unsigned int));
7982441aecdSOmair Javaid 
7992441aecdSOmair Javaid     if (error.Fail())
8002441aecdSOmair Javaid         return error;
8012441aecdSOmair Javaid 
8022441aecdSOmair Javaid     m_max_hwp_supported = (cap_val >> 8) & 0xff;
8032441aecdSOmair Javaid     m_max_hbp_supported = cap_val & 0xff;
8042441aecdSOmair Javaid     m_refresh_hwdebug_info = false;
8052441aecdSOmair Javaid 
8062441aecdSOmair Javaid     return error;
8072441aecdSOmair Javaid }
8082441aecdSOmair Javaid 
8092441aecdSOmair Javaid Error
8102441aecdSOmair Javaid NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, int hwb_index)
8112441aecdSOmair Javaid {
8122441aecdSOmair Javaid     Error error;
8132441aecdSOmair Javaid 
8142441aecdSOmair Javaid     lldb::addr_t *addr_buf;
8152441aecdSOmair Javaid     uint32_t *ctrl_buf;
8162441aecdSOmair Javaid 
8172441aecdSOmair Javaid     if (hwbType == eDREGTypeWATCH)
8182441aecdSOmair Javaid     {
8192441aecdSOmair Javaid         addr_buf = &m_hwp_regs[hwb_index].address;
8202441aecdSOmair Javaid         ctrl_buf = &m_hwp_regs[hwb_index].control;
8212441aecdSOmair Javaid 
8222441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
8232441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 1),
8242441aecdSOmair Javaid                 addr_buf, sizeof(unsigned int));
8252441aecdSOmair Javaid 
8262441aecdSOmair Javaid         if (error.Fail())
8272441aecdSOmair Javaid             return error;
8282441aecdSOmair Javaid 
8292441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
8302441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 2),
8312441aecdSOmair Javaid                 ctrl_buf, sizeof(unsigned int));
8322441aecdSOmair Javaid     }
8332441aecdSOmair Javaid     else
8342441aecdSOmair Javaid     {
8352441aecdSOmair Javaid         addr_buf = &m_hwp_regs[hwb_index].address;
8362441aecdSOmair Javaid         ctrl_buf = &m_hwp_regs[hwb_index].control;
8372441aecdSOmair Javaid 
8382441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
8392441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 1),
8402441aecdSOmair Javaid                 addr_buf, sizeof(unsigned int));
8412441aecdSOmair Javaid 
8422441aecdSOmair Javaid         if (error.Fail())
8432441aecdSOmair Javaid             return error;
8442441aecdSOmair Javaid 
8452441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
8462441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 2),
8472441aecdSOmair Javaid                 ctrl_buf, sizeof(unsigned int));
8482441aecdSOmair Javaid 
8492441aecdSOmair Javaid     }
8502441aecdSOmair Javaid 
8512441aecdSOmair Javaid     return error;
8522441aecdSOmair Javaid }
853c40e7b17STamas Berghammer 
854c40e7b17STamas Berghammer uint32_t
855c40e7b17STamas Berghammer NativeRegisterContextLinux_arm::CalculateFprOffset(const RegisterInfo* reg_info) const
856c40e7b17STamas Berghammer {
857c40e7b17STamas Berghammer     return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
858c40e7b17STamas Berghammer }
859c40e7b17STamas Berghammer 
860ce26b7a6STamas Berghammer Error
861ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoWriteRegisterValue(uint32_t offset,
862ce26b7a6STamas Berghammer                                                      const char* reg_name,
863ce26b7a6STamas Berghammer                                                      const RegisterValue &value)
864ce26b7a6STamas Berghammer {
865ce26b7a6STamas Berghammer     // PTRACE_POKEUSER don't work in the aarch64 liux kernel used on android devices (always return
866ce26b7a6STamas Berghammer     // "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR register set, modify
867ce26b7a6STamas Berghammer     // the requested register and write it back. This approach is about 4 times slower but the
868ce26b7a6STamas Berghammer     // performance overhead is negligible in comparision to processing time in lldb-server.
869ce26b7a6STamas Berghammer     assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
870ce26b7a6STamas Berghammer     if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
871ce26b7a6STamas Berghammer         return Error("Register isn't fit into the size of the GPR area");
872ce26b7a6STamas Berghammer 
873ce26b7a6STamas Berghammer     Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm));
874ce26b7a6STamas Berghammer     if (error.Fail())
875ce26b7a6STamas Berghammer         return error;
876ce26b7a6STamas Berghammer 
877ce26b7a6STamas Berghammer     m_gpr_arm[offset / sizeof(uint32_t)] = value.GetAsUInt32();
878ce26b7a6STamas Berghammer     return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm));
879ce26b7a6STamas Berghammer }
880ce26b7a6STamas Berghammer 
881ce26b7a6STamas Berghammer Error
882ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size)
883ce26b7a6STamas Berghammer {
884ce26b7a6STamas Berghammer     return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS,
885ce26b7a6STamas Berghammer                                              m_thread.GetID(),
886ce26b7a6STamas Berghammer                                              nullptr,
887ce26b7a6STamas Berghammer                                              buf,
888ce26b7a6STamas Berghammer                                              buf_size);
889ce26b7a6STamas Berghammer }
890ce26b7a6STamas Berghammer 
891ce26b7a6STamas Berghammer Error
892ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size)
893ce26b7a6STamas Berghammer {
894ce26b7a6STamas Berghammer     return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS,
895ce26b7a6STamas Berghammer                                              m_thread.GetID(),
896ce26b7a6STamas Berghammer                                              nullptr,
897ce26b7a6STamas Berghammer                                              buf,
898ce26b7a6STamas Berghammer                                              buf_size);
899ce26b7a6STamas Berghammer }
900ce26b7a6STamas Berghammer 
901068f8a7eSTamas Berghammer #endif // defined(__arm__)
902