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 
4434aa984c1SOmair 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())
454*d5510d1eSOmair Javaid         {
455*d5510d1eSOmair Javaid             m_hbr_regs[bp_index].address = 0;
456*d5510d1eSOmair Javaid             m_hbr_regs[bp_index].control &= ~1;
457*d5510d1eSOmair Javaid             m_hbr_regs[bp_index].refcount = 0;
458*d5510d1eSOmair Javaid 
4592441aecdSOmair Javaid             return LLDB_INVALID_INDEX32;
4602441aecdSOmair Javaid         }
461*d5510d1eSOmair Javaid     }
4622441aecdSOmair Javaid     else
4632441aecdSOmair Javaid         m_hbr_regs[bp_index].refcount++;
4642441aecdSOmair Javaid 
4652441aecdSOmair Javaid     return bp_index;
4662441aecdSOmair Javaid }
4672441aecdSOmair Javaid 
4682441aecdSOmair Javaid bool
4692441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearHardwareBreakpoint (uint32_t hw_idx)
4702441aecdSOmair Javaid {
4712441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
4722441aecdSOmair Javaid 
4732441aecdSOmair Javaid     if (log)
4742441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
4752441aecdSOmair Javaid 
4762441aecdSOmair Javaid     Error error;
4772441aecdSOmair Javaid 
4782441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
4792441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
4802441aecdSOmair Javaid 
4812441aecdSOmair Javaid     if (error.Fail())
4824aa984c1SOmair Javaid         return false;
4832441aecdSOmair Javaid 
4842441aecdSOmair Javaid     if (hw_idx >= m_max_hbp_supported)
4852441aecdSOmair Javaid         return false;
4862441aecdSOmair Javaid 
4872441aecdSOmair Javaid     // Update reference count if multiple references.
4882441aecdSOmair Javaid     if (m_hbr_regs[hw_idx].refcount > 1)
4892441aecdSOmair Javaid     {
4902441aecdSOmair Javaid         m_hbr_regs[hw_idx].refcount--;
4912441aecdSOmair Javaid         return true;
4922441aecdSOmair Javaid     }
4932441aecdSOmair Javaid     else if (m_hbr_regs[hw_idx].refcount == 1)
4942441aecdSOmair Javaid     {
495*d5510d1eSOmair Javaid         // Create a backup we can revert to in case of failure.
496*d5510d1eSOmair Javaid         lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
497*d5510d1eSOmair Javaid         uint32_t tempControl = m_hbr_regs[hw_idx].control;
498*d5510d1eSOmair Javaid         uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount;
499*d5510d1eSOmair Javaid 
5002441aecdSOmair Javaid         m_hbr_regs[hw_idx].control &= ~1;
5012441aecdSOmair Javaid         m_hbr_regs[hw_idx].address = 0;
5022441aecdSOmair Javaid         m_hbr_regs[hw_idx].refcount = 0;
5032441aecdSOmair Javaid 
5042441aecdSOmair Javaid         // PTRACE call to clear corresponding hardware breakpoint register.
5052441aecdSOmair Javaid         WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
5062441aecdSOmair Javaid 
5072441aecdSOmair Javaid         if (error.Fail())
508*d5510d1eSOmair Javaid         {
509*d5510d1eSOmair Javaid             m_hbr_regs[hw_idx].control = tempControl;
510*d5510d1eSOmair Javaid             m_hbr_regs[hw_idx].address = tempAddr;
511*d5510d1eSOmair Javaid             m_hbr_regs[hw_idx].refcount = tempRefCount;
512*d5510d1eSOmair Javaid 
5134aa984c1SOmair Javaid             return false;
514*d5510d1eSOmair Javaid         }
5152441aecdSOmair Javaid 
5162441aecdSOmair Javaid         return true;
5172441aecdSOmair Javaid     }
5182441aecdSOmair Javaid 
5192441aecdSOmair Javaid     return false;
5202441aecdSOmair Javaid }
5212441aecdSOmair Javaid 
5222441aecdSOmair Javaid uint32_t
5232441aecdSOmair Javaid NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints ()
5242441aecdSOmair Javaid {
5252441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
5262441aecdSOmair Javaid 
5272441aecdSOmair Javaid     if (log)
5282441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
5292441aecdSOmair Javaid 
5302441aecdSOmair Javaid     Error error;
5312441aecdSOmair Javaid 
5322441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
5332441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
5342441aecdSOmair Javaid 
5352441aecdSOmair Javaid     if (error.Fail())
5362441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
5372441aecdSOmair Javaid 
5382441aecdSOmair Javaid     return m_max_hwp_supported;
5392441aecdSOmair Javaid }
5402441aecdSOmair Javaid 
5412441aecdSOmair Javaid uint32_t
5422441aecdSOmair Javaid NativeRegisterContextLinux_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
5432441aecdSOmair Javaid {
5442441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
5452441aecdSOmair Javaid 
5462441aecdSOmair Javaid     if (log)
5472441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
5482441aecdSOmair Javaid 
5492441aecdSOmair Javaid     Error error;
5502441aecdSOmair Javaid 
5512441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
5522441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
5532441aecdSOmair Javaid 
5542441aecdSOmair Javaid     if (error.Fail())
5552441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
5562441aecdSOmair Javaid 
5572441aecdSOmair Javaid     uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
5582441aecdSOmair Javaid 
5592441aecdSOmair Javaid     // Check if we are setting watchpoint other than read/write/access
5602441aecdSOmair Javaid     // Also update watchpoint flag to match Arm write-read bit configuration.
5612441aecdSOmair Javaid     switch (watch_flags)
5622441aecdSOmair Javaid     {
5632441aecdSOmair Javaid         case 1:
5642441aecdSOmair Javaid             watch_flags = 2;
5652441aecdSOmair Javaid             break;
5662441aecdSOmair Javaid         case 2:
5672441aecdSOmair Javaid             watch_flags = 1;
5682441aecdSOmair Javaid             break;
5692441aecdSOmair Javaid         case 3:
5702441aecdSOmair Javaid             break;
5712441aecdSOmair Javaid         default:
5722441aecdSOmair Javaid             return LLDB_INVALID_INDEX32;
5732441aecdSOmair Javaid     }
5742441aecdSOmair Javaid 
5752441aecdSOmair Javaid     // Can't watch zero bytes
5762441aecdSOmair Javaid     // Can't watch more than 4 bytes per WVR/WCR pair
5772441aecdSOmair Javaid 
5782441aecdSOmair Javaid     if (size == 0 || size > 4)
5792441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
5802441aecdSOmair Javaid 
5812441aecdSOmair Javaid     // We can only watch up to four bytes that follow a 4 byte aligned address
5822441aecdSOmair Javaid     // per watchpoint register pair, so make sure we can properly encode this.
5832441aecdSOmair Javaid     addr_word_offset = addr % 4;
5842441aecdSOmair Javaid     byte_mask = ((1u << size) - 1u) << addr_word_offset;
5852441aecdSOmair Javaid 
5862441aecdSOmair Javaid     // Check if we need multiple watchpoint register
5872441aecdSOmair Javaid     if (byte_mask > 0xfu)
5882441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
5892441aecdSOmair Javaid 
5902441aecdSOmair Javaid     // Setup control value
5912441aecdSOmair Javaid     // Make the byte_mask into a valid Byte Address Select mask
5922441aecdSOmair Javaid     control_value = byte_mask << 5;
5932441aecdSOmair Javaid 
5942441aecdSOmair Javaid     //Turn on appropriate watchpoint flags read or write
5952441aecdSOmair Javaid     control_value |= (watch_flags << 3);
5962441aecdSOmair Javaid 
5972441aecdSOmair Javaid     // Enable this watchpoint and make it stop in privileged or user mode;
5982441aecdSOmair Javaid     control_value |= 7;
5992441aecdSOmair Javaid 
6002441aecdSOmair Javaid     // Make sure bits 1:0 are clear in our address
6012441aecdSOmair Javaid     addr &= ~((lldb::addr_t)3);
6022441aecdSOmair Javaid 
6032441aecdSOmair Javaid     // Iterate over stored watchpoints
6042441aecdSOmair Javaid     // Find a free wp_index or update reference count if duplicate.
6052441aecdSOmair Javaid     wp_index = LLDB_INVALID_INDEX32;
6062441aecdSOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
6072441aecdSOmair Javaid     {
6082441aecdSOmair Javaid         if ((m_hwp_regs[i].control & 1) == 0)
6092441aecdSOmair Javaid         {
6102441aecdSOmair Javaid             wp_index = i; // Mark last free slot
6112441aecdSOmair Javaid         }
6122441aecdSOmair Javaid         else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
6132441aecdSOmair Javaid         {
6142441aecdSOmair Javaid             wp_index = i; // Mark duplicate index
6152441aecdSOmair Javaid             break; // Stop searching here
6162441aecdSOmair Javaid         }
6172441aecdSOmair Javaid     }
6182441aecdSOmair Javaid 
6192441aecdSOmair Javaid      if (wp_index == LLDB_INVALID_INDEX32)
6202441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
6212441aecdSOmair Javaid 
6222441aecdSOmair Javaid     // Add new or update existing watchpoint
6232441aecdSOmair Javaid     if ((m_hwp_regs[wp_index].control & 1) == 0)
6242441aecdSOmair Javaid     {
6252441aecdSOmair Javaid         // Update watchpoint in local cache
6262441aecdSOmair Javaid         m_hwp_regs[wp_index].address = addr;
6272441aecdSOmair Javaid         m_hwp_regs[wp_index].control = control_value;
6282441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount = 1;
6292441aecdSOmair Javaid 
6302441aecdSOmair Javaid         // PTRACE call to set corresponding watchpoint register.
6312441aecdSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
6322441aecdSOmair Javaid 
6332441aecdSOmair Javaid         if (error.Fail())
634*d5510d1eSOmair Javaid         {
635*d5510d1eSOmair Javaid             m_hwp_regs[wp_index].address = 0;
636*d5510d1eSOmair Javaid             m_hwp_regs[wp_index].control &= ~1;
637*d5510d1eSOmair Javaid             m_hwp_regs[wp_index].refcount = 0;
638*d5510d1eSOmair Javaid 
6392441aecdSOmair Javaid             return LLDB_INVALID_INDEX32;
6402441aecdSOmair Javaid         }
641*d5510d1eSOmair Javaid     }
6422441aecdSOmair Javaid     else
6432441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount++;
6442441aecdSOmair Javaid 
6452441aecdSOmair Javaid     return wp_index;
6462441aecdSOmair Javaid }
6472441aecdSOmair Javaid 
6482441aecdSOmair Javaid bool
6492441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearHardwareWatchpoint (uint32_t wp_index)
6502441aecdSOmair Javaid {
6512441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
6522441aecdSOmair Javaid 
6532441aecdSOmair Javaid     if (log)
6542441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
6552441aecdSOmair Javaid 
6562441aecdSOmair Javaid     Error error;
6572441aecdSOmair Javaid 
6582441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
6592441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
6602441aecdSOmair Javaid 
6612441aecdSOmair Javaid     if (error.Fail())
6624aa984c1SOmair Javaid         return false;
6632441aecdSOmair Javaid 
6642441aecdSOmair Javaid     if (wp_index >= m_max_hwp_supported)
6652441aecdSOmair Javaid         return false;
6662441aecdSOmair Javaid 
6672441aecdSOmair Javaid     // Update reference count if multiple references.
6682441aecdSOmair Javaid     if (m_hwp_regs[wp_index].refcount > 1)
6692441aecdSOmair Javaid     {
6702441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount--;
6712441aecdSOmair Javaid         return true;
6722441aecdSOmair Javaid     }
6732441aecdSOmair Javaid     else if (m_hwp_regs[wp_index].refcount == 1)
6742441aecdSOmair Javaid     {
675*d5510d1eSOmair Javaid         // Create a backup we can revert to in case of failure.
676*d5510d1eSOmair Javaid         lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
677*d5510d1eSOmair Javaid         uint32_t tempControl = m_hwp_regs[wp_index].control;
678*d5510d1eSOmair Javaid         uint32_t tempRefCount = m_hwp_regs[wp_index].refcount;
679*d5510d1eSOmair Javaid 
6802441aecdSOmair Javaid         // Update watchpoint in local cache
6812441aecdSOmair Javaid         m_hwp_regs[wp_index].control &= ~1;
6822441aecdSOmair Javaid         m_hwp_regs[wp_index].address = 0;
6832441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount = 0;
6842441aecdSOmair Javaid 
6852441aecdSOmair Javaid         // Ptrace call to update hardware debug registers
6862441aecdSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
6872441aecdSOmair Javaid 
6882441aecdSOmair Javaid         if (error.Fail())
689*d5510d1eSOmair Javaid         {
690*d5510d1eSOmair Javaid             m_hwp_regs[wp_index].control = tempControl;
691*d5510d1eSOmair Javaid             m_hwp_regs[wp_index].address = tempAddr;
692*d5510d1eSOmair Javaid             m_hwp_regs[wp_index].refcount = tempRefCount;
693*d5510d1eSOmair Javaid 
6942441aecdSOmair Javaid             return false;
695*d5510d1eSOmair Javaid         }
6962441aecdSOmair Javaid 
6972441aecdSOmair Javaid         return true;
6982441aecdSOmair Javaid     }
6992441aecdSOmair Javaid 
7002441aecdSOmair Javaid     return false;
7012441aecdSOmair Javaid }
7022441aecdSOmair Javaid 
7032441aecdSOmair Javaid Error
7042441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints ()
7052441aecdSOmair Javaid {
7062441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
7072441aecdSOmair Javaid 
7082441aecdSOmair Javaid     if (log)
7092441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7102441aecdSOmair Javaid 
7112441aecdSOmair Javaid     Error error;
7122441aecdSOmair Javaid 
7132441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
7142441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
7152441aecdSOmair Javaid 
7162441aecdSOmair Javaid     if (error.Fail())
7172441aecdSOmair Javaid         return error;
7182441aecdSOmair Javaid 
719*d5510d1eSOmair Javaid     lldb::addr_t tempAddr = 0;
720*d5510d1eSOmair Javaid     uint32_t tempControl = 0, tempRefCount = 0;
721*d5510d1eSOmair Javaid 
7222441aecdSOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
7232441aecdSOmair Javaid     {
7242441aecdSOmair Javaid         if (m_hwp_regs[i].control & 0x01)
7252441aecdSOmair Javaid         {
726*d5510d1eSOmair Javaid             // Create a backup we can revert to in case of failure.
727*d5510d1eSOmair Javaid             tempAddr = m_hwp_regs[i].address;
728*d5510d1eSOmair Javaid             tempControl = m_hwp_regs[i].control;
729*d5510d1eSOmair Javaid             tempRefCount = m_hwp_regs[i].refcount;
730*d5510d1eSOmair Javaid 
7312441aecdSOmair Javaid             // Clear watchpoints in local cache
7322441aecdSOmair Javaid             m_hwp_regs[i].control &= ~1;
7332441aecdSOmair Javaid             m_hwp_regs[i].address = 0;
7342441aecdSOmair Javaid             m_hwp_regs[i].refcount = 0;
7352441aecdSOmair Javaid 
7362441aecdSOmair Javaid             // Ptrace call to update hardware debug registers
7372441aecdSOmair Javaid             error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
7382441aecdSOmair Javaid 
7392441aecdSOmair Javaid             if (error.Fail())
740*d5510d1eSOmair Javaid             {
741*d5510d1eSOmair Javaid                 m_hwp_regs[i].control = tempControl;
742*d5510d1eSOmair Javaid                 m_hwp_regs[i].address = tempAddr;
743*d5510d1eSOmair Javaid                 m_hwp_regs[i].refcount = tempRefCount;
744*d5510d1eSOmair Javaid 
7452441aecdSOmair Javaid                 return error;
7462441aecdSOmair Javaid             }
7472441aecdSOmair Javaid         }
748*d5510d1eSOmair Javaid     }
7492441aecdSOmair Javaid 
7502441aecdSOmair Javaid     return Error();
7512441aecdSOmair Javaid }
7522441aecdSOmair Javaid 
7532441aecdSOmair Javaid uint32_t
7542441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index)
7552441aecdSOmair Javaid {
7562441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
7572441aecdSOmair Javaid 
7582441aecdSOmair Javaid     if (log)
7592441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7602441aecdSOmair Javaid 
7612441aecdSOmair Javaid     switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f)
7622441aecdSOmair Javaid     {
7632441aecdSOmair Javaid         case 0x01:
7642441aecdSOmair Javaid             return 1;
7652441aecdSOmair Javaid         case 0x03:
7662441aecdSOmair Javaid             return 2;
7672441aecdSOmair Javaid         case 0x07:
7682441aecdSOmair Javaid             return 3;
7692441aecdSOmair Javaid         case 0x0f:
7702441aecdSOmair Javaid             return 4;
7712441aecdSOmair Javaid         default:
7722441aecdSOmair Javaid             return 0;
7732441aecdSOmair Javaid     }
7742441aecdSOmair Javaid }
7752441aecdSOmair Javaid bool
7762441aecdSOmair Javaid NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index)
7772441aecdSOmair Javaid {
7782441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
7792441aecdSOmair Javaid 
7802441aecdSOmair Javaid     if (log)
7812441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7822441aecdSOmair Javaid 
7832441aecdSOmair Javaid     if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
7842441aecdSOmair Javaid         return true;
7852441aecdSOmair Javaid     else
7862441aecdSOmair Javaid         return false;
7872441aecdSOmair Javaid }
7882441aecdSOmair Javaid 
7892441aecdSOmair Javaid Error
7902441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
7912441aecdSOmair Javaid {
7922441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
7932441aecdSOmair Javaid 
7942441aecdSOmair Javaid     if (log)
7952441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7962441aecdSOmair Javaid 
7972441aecdSOmair Javaid     uint32_t watch_size;
7982441aecdSOmair Javaid     lldb::addr_t watch_addr;
7992441aecdSOmair Javaid 
8002441aecdSOmair Javaid     for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
8012441aecdSOmair Javaid     {
8022441aecdSOmair Javaid         watch_size = GetWatchpointSize (wp_index);
8032441aecdSOmair Javaid         watch_addr = m_hwp_regs[wp_index].address;
8042441aecdSOmair Javaid 
8052441aecdSOmair Javaid         if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
8062441aecdSOmair Javaid             && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
8072441aecdSOmair Javaid         {
8082441aecdSOmair Javaid             return Error();
8092441aecdSOmair Javaid         }
8102441aecdSOmair Javaid     }
8112441aecdSOmair Javaid 
8122441aecdSOmair Javaid     wp_index = LLDB_INVALID_INDEX32;
8132441aecdSOmair Javaid     return Error();
8142441aecdSOmair Javaid }
8152441aecdSOmair Javaid 
8162441aecdSOmair Javaid lldb::addr_t
8172441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointAddress (uint32_t wp_index)
8182441aecdSOmair Javaid {
8192441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
8202441aecdSOmair Javaid 
8212441aecdSOmair Javaid     if (log)
8222441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
8232441aecdSOmair Javaid 
8242441aecdSOmair Javaid     if (wp_index >= m_max_hwp_supported)
8252441aecdSOmair Javaid         return LLDB_INVALID_ADDRESS;
8262441aecdSOmair Javaid 
8272441aecdSOmair Javaid     if (WatchpointIsEnabled(wp_index))
8282441aecdSOmair Javaid         return m_hwp_regs[wp_index].address;
8292441aecdSOmair Javaid     else
8302441aecdSOmair Javaid         return LLDB_INVALID_ADDRESS;
8312441aecdSOmair Javaid }
8322441aecdSOmair Javaid 
8332441aecdSOmair Javaid Error
8342441aecdSOmair Javaid NativeRegisterContextLinux_arm::ReadHardwareDebugInfo()
8352441aecdSOmair Javaid {
8362441aecdSOmair Javaid     Error error;
8372441aecdSOmair Javaid 
8382441aecdSOmair Javaid     if (!m_refresh_hwdebug_info)
8392441aecdSOmair Javaid     {
8402441aecdSOmair Javaid         return Error();
8412441aecdSOmair Javaid     }
8422441aecdSOmair Javaid 
8432441aecdSOmair Javaid     unsigned int cap_val;
8442441aecdSOmair Javaid 
8452441aecdSOmair Javaid     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), nullptr, &cap_val, sizeof(unsigned int));
8462441aecdSOmair Javaid 
8472441aecdSOmair Javaid     if (error.Fail())
8482441aecdSOmair Javaid         return error;
8492441aecdSOmair Javaid 
8502441aecdSOmair Javaid     m_max_hwp_supported = (cap_val >> 8) & 0xff;
8512441aecdSOmair Javaid     m_max_hbp_supported = cap_val & 0xff;
8522441aecdSOmair Javaid     m_refresh_hwdebug_info = false;
8532441aecdSOmair Javaid 
8542441aecdSOmair Javaid     return error;
8552441aecdSOmair Javaid }
8562441aecdSOmair Javaid 
8572441aecdSOmair Javaid Error
8582441aecdSOmair Javaid NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, int hwb_index)
8592441aecdSOmair Javaid {
8602441aecdSOmair Javaid     Error error;
8612441aecdSOmair Javaid 
8622441aecdSOmair Javaid     lldb::addr_t *addr_buf;
8632441aecdSOmair Javaid     uint32_t *ctrl_buf;
8642441aecdSOmair Javaid 
8652441aecdSOmair Javaid     if (hwbType == eDREGTypeWATCH)
8662441aecdSOmair Javaid     {
8672441aecdSOmair Javaid         addr_buf = &m_hwp_regs[hwb_index].address;
8682441aecdSOmair Javaid         ctrl_buf = &m_hwp_regs[hwb_index].control;
8692441aecdSOmair Javaid 
8702441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
8712441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 1),
8722441aecdSOmair Javaid                 addr_buf, sizeof(unsigned int));
8732441aecdSOmair Javaid 
8742441aecdSOmair Javaid         if (error.Fail())
8752441aecdSOmair Javaid             return error;
8762441aecdSOmair Javaid 
8772441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
8782441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 2),
8792441aecdSOmair Javaid                 ctrl_buf, sizeof(unsigned int));
8802441aecdSOmair Javaid     }
8812441aecdSOmair Javaid     else
8822441aecdSOmair Javaid     {
8832441aecdSOmair Javaid         addr_buf = &m_hwp_regs[hwb_index].address;
8842441aecdSOmair Javaid         ctrl_buf = &m_hwp_regs[hwb_index].control;
8852441aecdSOmair Javaid 
8862441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
8872441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 1),
8882441aecdSOmair Javaid                 addr_buf, sizeof(unsigned int));
8892441aecdSOmair Javaid 
8902441aecdSOmair Javaid         if (error.Fail())
8912441aecdSOmair Javaid             return error;
8922441aecdSOmair Javaid 
8932441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
8942441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 2),
8952441aecdSOmair Javaid                 ctrl_buf, sizeof(unsigned int));
8962441aecdSOmair Javaid 
8972441aecdSOmair Javaid     }
8982441aecdSOmair Javaid 
8992441aecdSOmair Javaid     return error;
9002441aecdSOmair Javaid }
901c40e7b17STamas Berghammer 
902c40e7b17STamas Berghammer uint32_t
903c40e7b17STamas Berghammer NativeRegisterContextLinux_arm::CalculateFprOffset(const RegisterInfo* reg_info) const
904c40e7b17STamas Berghammer {
905c40e7b17STamas Berghammer     return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
906c40e7b17STamas Berghammer }
907c40e7b17STamas Berghammer 
908ce26b7a6STamas Berghammer Error
909ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoWriteRegisterValue(uint32_t offset,
910ce26b7a6STamas Berghammer                                                      const char* reg_name,
911ce26b7a6STamas Berghammer                                                      const RegisterValue &value)
912ce26b7a6STamas Berghammer {
913ce26b7a6STamas Berghammer     // PTRACE_POKEUSER don't work in the aarch64 liux kernel used on android devices (always return
914ce26b7a6STamas Berghammer     // "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR register set, modify
915ce26b7a6STamas Berghammer     // the requested register and write it back. This approach is about 4 times slower but the
916ce26b7a6STamas Berghammer     // performance overhead is negligible in comparision to processing time in lldb-server.
917ce26b7a6STamas Berghammer     assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
918ce26b7a6STamas Berghammer     if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
919ce26b7a6STamas Berghammer         return Error("Register isn't fit into the size of the GPR area");
920ce26b7a6STamas Berghammer 
921ce26b7a6STamas Berghammer     Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm));
922ce26b7a6STamas Berghammer     if (error.Fail())
923ce26b7a6STamas Berghammer         return error;
924ce26b7a6STamas Berghammer 
925ce26b7a6STamas Berghammer     m_gpr_arm[offset / sizeof(uint32_t)] = value.GetAsUInt32();
926ce26b7a6STamas Berghammer     return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm));
927ce26b7a6STamas Berghammer }
928ce26b7a6STamas Berghammer 
929ce26b7a6STamas Berghammer Error
930ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size)
931ce26b7a6STamas Berghammer {
932ce26b7a6STamas Berghammer     return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS,
933ce26b7a6STamas Berghammer                                              m_thread.GetID(),
934ce26b7a6STamas Berghammer                                              nullptr,
935ce26b7a6STamas Berghammer                                              buf,
936ce26b7a6STamas Berghammer                                              buf_size);
937ce26b7a6STamas Berghammer }
938ce26b7a6STamas Berghammer 
939ce26b7a6STamas Berghammer Error
940ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size)
941ce26b7a6STamas Berghammer {
942ce26b7a6STamas Berghammer     return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS,
943ce26b7a6STamas Berghammer                                              m_thread.GetID(),
944ce26b7a6STamas Berghammer                                              nullptr,
945ce26b7a6STamas Berghammer                                              buf,
946ce26b7a6STamas Berghammer                                              buf_size);
947ce26b7a6STamas Berghammer }
948ce26b7a6STamas Berghammer 
949068f8a7eSTamas Berghammer #endif // defined(__arm__)
950