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,
103b4e95a50STamas Berghammer     fpu_d0_arm,
104b4e95a50STamas Berghammer     fpu_d1_arm,
105b4e95a50STamas Berghammer     fpu_d2_arm,
106b4e95a50STamas Berghammer     fpu_d3_arm,
107b4e95a50STamas Berghammer     fpu_d4_arm,
108b4e95a50STamas Berghammer     fpu_d5_arm,
109b4e95a50STamas Berghammer     fpu_d6_arm,
110b4e95a50STamas Berghammer     fpu_d7_arm,
111b4e95a50STamas Berghammer     fpu_d8_arm,
112b4e95a50STamas Berghammer     fpu_d9_arm,
113b4e95a50STamas Berghammer     fpu_d10_arm,
114b4e95a50STamas Berghammer     fpu_d11_arm,
115b4e95a50STamas Berghammer     fpu_d12_arm,
116b4e95a50STamas Berghammer     fpu_d13_arm,
117b4e95a50STamas Berghammer     fpu_d14_arm,
118b4e95a50STamas Berghammer     fpu_d15_arm,
119b4e95a50STamas Berghammer     fpu_d16_arm,
120b4e95a50STamas Berghammer     fpu_d17_arm,
121b4e95a50STamas Berghammer     fpu_d18_arm,
122b4e95a50STamas Berghammer     fpu_d19_arm,
123b4e95a50STamas Berghammer     fpu_d20_arm,
124b4e95a50STamas Berghammer     fpu_d21_arm,
125b4e95a50STamas Berghammer     fpu_d22_arm,
126b4e95a50STamas Berghammer     fpu_d23_arm,
127b4e95a50STamas Berghammer     fpu_d24_arm,
128b4e95a50STamas Berghammer     fpu_d25_arm,
129b4e95a50STamas Berghammer     fpu_d26_arm,
130b4e95a50STamas Berghammer     fpu_d27_arm,
131b4e95a50STamas Berghammer     fpu_d28_arm,
132b4e95a50STamas Berghammer     fpu_d29_arm,
133b4e95a50STamas Berghammer     fpu_d30_arm,
134b4e95a50STamas Berghammer     fpu_d31_arm,
135b4e95a50STamas Berghammer     fpu_q0_arm,
136b4e95a50STamas Berghammer     fpu_q1_arm,
137b4e95a50STamas Berghammer     fpu_q2_arm,
138b4e95a50STamas Berghammer     fpu_q3_arm,
139b4e95a50STamas Berghammer     fpu_q4_arm,
140b4e95a50STamas Berghammer     fpu_q5_arm,
141b4e95a50STamas Berghammer     fpu_q6_arm,
142b4e95a50STamas Berghammer     fpu_q7_arm,
143b4e95a50STamas Berghammer     fpu_q8_arm,
144b4e95a50STamas Berghammer     fpu_q9_arm,
145b4e95a50STamas Berghammer     fpu_q10_arm,
146b4e95a50STamas Berghammer     fpu_q11_arm,
147b4e95a50STamas Berghammer     fpu_q12_arm,
148b4e95a50STamas Berghammer     fpu_q13_arm,
149b4e95a50STamas Berghammer     fpu_q14_arm,
150b4e95a50STamas Berghammer     fpu_q15_arm,
1513f57216cSOmair Javaid     LLDB_INVALID_REGNUM // register sets need to end with this flag
1523f57216cSOmair Javaid };
1533f57216cSOmair Javaid static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \
1543f57216cSOmair Javaid               "g_fpu_regnums_arm has wrong number of register infos");
1553f57216cSOmair Javaid 
1563f57216cSOmair Javaid namespace {
1573f57216cSOmair Javaid     // Number of register sets provided by this context.
1583f57216cSOmair Javaid     enum
1593f57216cSOmair Javaid     {
1603f57216cSOmair Javaid         k_num_register_sets = 2
1613f57216cSOmair Javaid     };
1623f57216cSOmair Javaid }
1633f57216cSOmair Javaid 
1643f57216cSOmair Javaid // Register sets for arm.
1653f57216cSOmair Javaid static const RegisterSet
1663f57216cSOmair Javaid g_reg_sets_arm[k_num_register_sets] =
1673f57216cSOmair Javaid {
1683f57216cSOmair Javaid     { "General Purpose Registers",  "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm },
1693f57216cSOmair Javaid     { "Floating Point Registers",   "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm }
1703f57216cSOmair Javaid };
1713f57216cSOmair Javaid 
172068f8a7eSTamas Berghammer NativeRegisterContextLinux*
173068f8a7eSTamas Berghammer NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
1743f57216cSOmair Javaid                                                                  NativeThreadProtocol &native_thread,
175068f8a7eSTamas Berghammer                                                                  uint32_t concrete_frame_idx)
1763f57216cSOmair Javaid {
177068f8a7eSTamas Berghammer     return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx);
178068f8a7eSTamas Berghammer }
179068f8a7eSTamas Berghammer 
180068f8a7eSTamas Berghammer NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm (const ArchSpec& target_arch,
181068f8a7eSTamas Berghammer                                                                 NativeThreadProtocol &native_thread,
182068f8a7eSTamas Berghammer                                                                 uint32_t concrete_frame_idx) :
183068f8a7eSTamas Berghammer     NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm(target_arch))
184068f8a7eSTamas Berghammer {
185068f8a7eSTamas Berghammer     switch (target_arch.GetMachine())
1863f57216cSOmair Javaid     {
1873f57216cSOmair Javaid         case llvm::Triple::arm:
1883f57216cSOmair Javaid             m_reg_info.num_registers     = k_num_registers_arm;
1893f57216cSOmair Javaid             m_reg_info.num_gpr_registers = k_num_gpr_registers_arm;
1903f57216cSOmair Javaid             m_reg_info.num_fpr_registers = k_num_fpr_registers_arm;
1913f57216cSOmair Javaid             m_reg_info.last_gpr          = k_last_gpr_arm;
1923f57216cSOmair Javaid             m_reg_info.first_fpr         = k_first_fpr_arm;
1933f57216cSOmair Javaid             m_reg_info.last_fpr          = k_last_fpr_arm;
1943f57216cSOmair Javaid             m_reg_info.first_fpr_v       = fpu_s0_arm;
1953f57216cSOmair Javaid             m_reg_info.last_fpr_v        = fpu_s31_arm;
1963f57216cSOmair Javaid             m_reg_info.gpr_flags         = gpr_cpsr_arm;
1973f57216cSOmair Javaid             break;
1983f57216cSOmair Javaid         default:
1993f57216cSOmair Javaid             assert(false && "Unhandled target architecture.");
2003f57216cSOmair Javaid             break;
2013f57216cSOmair Javaid     }
2023f57216cSOmair Javaid 
2033f57216cSOmair Javaid     ::memset(&m_fpr, 0, sizeof (m_fpr));
2043f57216cSOmair Javaid     ::memset(&m_gpr_arm, 0, sizeof (m_gpr_arm));
2052441aecdSOmair Javaid     ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs));
2062441aecdSOmair Javaid 
2072441aecdSOmair Javaid     // 16 is just a maximum value, query hardware for actual watchpoint count
2082441aecdSOmair Javaid     m_max_hwp_supported = 16;
2092441aecdSOmair Javaid     m_max_hbp_supported = 16;
2102441aecdSOmair Javaid     m_refresh_hwdebug_info = true;
2113f57216cSOmair Javaid }
2123f57216cSOmair Javaid 
2133f57216cSOmair Javaid uint32_t
2143f57216cSOmair Javaid NativeRegisterContextLinux_arm::GetRegisterSetCount () const
2153f57216cSOmair Javaid {
2163f57216cSOmair Javaid     return k_num_register_sets;
2173f57216cSOmair Javaid }
2183f57216cSOmair Javaid 
2191f149204STamas Berghammer uint32_t
2201f149204STamas Berghammer NativeRegisterContextLinux_arm::GetUserRegisterCount() const
2211f149204STamas Berghammer {
2221f149204STamas Berghammer     uint32_t count = 0;
2231f149204STamas Berghammer     for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
2241f149204STamas Berghammer         count += g_reg_sets_arm[set_index].num_registers;
2251f149204STamas Berghammer     return count;
2261f149204STamas Berghammer }
2271f149204STamas Berghammer 
2283f57216cSOmair Javaid const RegisterSet *
2293f57216cSOmair Javaid NativeRegisterContextLinux_arm::GetRegisterSet (uint32_t set_index) const
2303f57216cSOmair Javaid {
2313f57216cSOmair Javaid     if (set_index < k_num_register_sets)
2323f57216cSOmair Javaid         return &g_reg_sets_arm[set_index];
2333f57216cSOmair Javaid 
2343f57216cSOmair Javaid     return nullptr;
2353f57216cSOmair Javaid }
2363f57216cSOmair Javaid 
2373f57216cSOmair Javaid Error
2383f57216cSOmair Javaid NativeRegisterContextLinux_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
2393f57216cSOmair Javaid {
2403f57216cSOmair Javaid     Error error;
2413f57216cSOmair Javaid 
2423f57216cSOmair Javaid     if (!reg_info)
2433f57216cSOmair Javaid     {
2443f57216cSOmair Javaid         error.SetErrorString ("reg_info NULL");
2453f57216cSOmair Javaid         return error;
2463f57216cSOmair Javaid     }
2473f57216cSOmair Javaid 
2483f57216cSOmair Javaid     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
2493f57216cSOmair Javaid 
2503f57216cSOmair Javaid     if (IsFPR(reg))
2513f57216cSOmair Javaid     {
252068f8a7eSTamas Berghammer         error = ReadFPR();
253068f8a7eSTamas Berghammer         if (error.Fail())
2543f57216cSOmair Javaid             return error;
2553f57216cSOmair Javaid     }
2563f57216cSOmair Javaid     else
2573f57216cSOmair Javaid     {
2583f57216cSOmair Javaid         uint32_t full_reg = reg;
2593f57216cSOmair Javaid         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
2603f57216cSOmair Javaid 
2613f57216cSOmair Javaid         if (is_subreg)
2623f57216cSOmair Javaid         {
2633f57216cSOmair Javaid             // Read the full aligned 64-bit register.
2643f57216cSOmair Javaid             full_reg = reg_info->invalidate_regs[0];
2653f57216cSOmair Javaid         }
2663f57216cSOmair Javaid 
2673f57216cSOmair Javaid         error = ReadRegisterRaw(full_reg, reg_value);
2683f57216cSOmair Javaid 
2693f57216cSOmair Javaid         if (error.Success ())
2703f57216cSOmair Javaid         {
2713f57216cSOmair Javaid             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
2723f57216cSOmair Javaid             if (is_subreg && (reg_info->byte_offset & 0x1))
2733f57216cSOmair Javaid                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
2743f57216cSOmair Javaid 
2753f57216cSOmair Javaid             // If our return byte size was greater than the return value reg size, then
2763f57216cSOmair Javaid             // use the type specified by reg_info rather than the uint64_t default
2773f57216cSOmair Javaid             if (reg_value.GetByteSize() > reg_info->byte_size)
2783f57216cSOmair Javaid                 reg_value.SetType(reg_info);
2793f57216cSOmair Javaid         }
2803f57216cSOmair Javaid         return error;
2813f57216cSOmair Javaid     }
2823f57216cSOmair Javaid 
2833f57216cSOmair Javaid     // Get pointer to m_fpr variable and set the data from it.
284c40e7b17STamas Berghammer     uint32_t fpr_offset = CalculateFprOffset(reg_info);
285c40e7b17STamas Berghammer     assert (fpr_offset < sizeof m_fpr);
286c40e7b17STamas Berghammer     uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
2873f57216cSOmair Javaid     switch (reg_info->byte_size)
2883f57216cSOmair Javaid     {
2893f57216cSOmair Javaid         case 2:
2903f57216cSOmair Javaid             reg_value.SetUInt16(*(uint16_t *)src);
2913f57216cSOmair Javaid             break;
2923f57216cSOmair Javaid         case 4:
2933f57216cSOmair Javaid             reg_value.SetUInt32(*(uint32_t *)src);
2943f57216cSOmair Javaid             break;
2953f57216cSOmair Javaid         case 8:
2963f57216cSOmair Javaid             reg_value.SetUInt64(*(uint64_t *)src);
2973f57216cSOmair Javaid             break;
298b4e95a50STamas Berghammer         case 16:
299b4e95a50STamas Berghammer             reg_value.SetBytes(src, 16, GetByteOrder());
300b4e95a50STamas Berghammer             break;
3013f57216cSOmair Javaid         default:
3023f57216cSOmair Javaid             assert(false && "Unhandled data size.");
3033f57216cSOmair Javaid             error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
3043f57216cSOmair Javaid             break;
3053f57216cSOmair Javaid     }
3063f57216cSOmair Javaid 
3073f57216cSOmair Javaid     return error;
3083f57216cSOmair Javaid }
3093f57216cSOmair Javaid 
3103f57216cSOmair Javaid Error
3113f57216cSOmair Javaid NativeRegisterContextLinux_arm::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
3123f57216cSOmair Javaid {
3133f57216cSOmair Javaid     if (!reg_info)
3143f57216cSOmair Javaid         return Error ("reg_info NULL");
3153f57216cSOmair Javaid 
3163f57216cSOmair Javaid     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
3173f57216cSOmair Javaid     if (reg_index == LLDB_INVALID_REGNUM)
3183f57216cSOmair Javaid         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
3193f57216cSOmair Javaid 
3203f57216cSOmair Javaid     if (IsGPR(reg_index))
3213f57216cSOmair Javaid         return WriteRegisterRaw(reg_index, reg_value);
3223f57216cSOmair Javaid 
3233f57216cSOmair Javaid     if (IsFPR(reg_index))
3243f57216cSOmair Javaid     {
3253f57216cSOmair Javaid         // Get pointer to m_fpr variable and set the data to it.
326c40e7b17STamas Berghammer         uint32_t fpr_offset = CalculateFprOffset(reg_info);
327c40e7b17STamas Berghammer         assert (fpr_offset < sizeof m_fpr);
328c40e7b17STamas Berghammer         uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
3293f57216cSOmair Javaid         switch (reg_info->byte_size)
3303f57216cSOmair Javaid         {
3313f57216cSOmair Javaid             case 2:
3323f57216cSOmair Javaid                 *(uint16_t *)dst = reg_value.GetAsUInt16();
3333f57216cSOmair Javaid                 break;
3343f57216cSOmair Javaid             case 4:
3353f57216cSOmair Javaid                 *(uint32_t *)dst = reg_value.GetAsUInt32();
3363f57216cSOmair Javaid                 break;
3373f57216cSOmair Javaid             case 8:
3383f57216cSOmair Javaid                 *(uint64_t *)dst = reg_value.GetAsUInt64();
3393f57216cSOmair Javaid                 break;
3403f57216cSOmair Javaid             default:
3413f57216cSOmair Javaid                 assert(false && "Unhandled data size.");
3423f57216cSOmair Javaid                 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
3433f57216cSOmair Javaid         }
3443f57216cSOmair Javaid 
345068f8a7eSTamas Berghammer         Error error = WriteFPR();
346068f8a7eSTamas Berghammer         if (error.Fail())
347068f8a7eSTamas Berghammer             return error;
3483f57216cSOmair Javaid 
3493f57216cSOmair Javaid         return Error ();
3503f57216cSOmair Javaid     }
3513f57216cSOmair Javaid 
3523f57216cSOmair Javaid     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
3533f57216cSOmair Javaid }
3543f57216cSOmair Javaid 
3553f57216cSOmair Javaid Error
3563f57216cSOmair Javaid NativeRegisterContextLinux_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
3573f57216cSOmair Javaid {
3583f57216cSOmair Javaid     Error error;
3593f57216cSOmair Javaid 
3603f57216cSOmair Javaid     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
3613f57216cSOmair Javaid     if (!data_sp)
362bef47e49SGreg Clayton         return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, (uint64_t)REG_CONTEXT_SIZE);
3633f57216cSOmair Javaid 
364068f8a7eSTamas Berghammer     error = ReadGPR();
365068f8a7eSTamas Berghammer     if (error.Fail())
3663f57216cSOmair Javaid         return error;
3673f57216cSOmair Javaid 
368068f8a7eSTamas Berghammer     error = ReadFPR();
369068f8a7eSTamas Berghammer     if (error.Fail())
3703f57216cSOmair Javaid         return error;
3713f57216cSOmair Javaid 
3723f57216cSOmair Javaid     uint8_t *dst = data_sp->GetBytes ();
3733f57216cSOmair Javaid     if (dst == nullptr)
3743f57216cSOmair Javaid     {
375bef47e49SGreg Clayton         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", (uint64_t)REG_CONTEXT_SIZE);
3763f57216cSOmair Javaid         return error;
3773f57216cSOmair Javaid     }
3783f57216cSOmair Javaid 
3793f57216cSOmair Javaid     ::memcpy (dst, &m_gpr_arm, GetGPRSize());
3803f57216cSOmair Javaid     dst += GetGPRSize();
3813f57216cSOmair Javaid     ::memcpy (dst, &m_fpr, sizeof(m_fpr));
3823f57216cSOmair Javaid 
3833f57216cSOmair Javaid     return error;
3843f57216cSOmair Javaid }
3853f57216cSOmair Javaid 
3863f57216cSOmair Javaid Error
3873f57216cSOmair Javaid NativeRegisterContextLinux_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
3883f57216cSOmair Javaid {
3893f57216cSOmair Javaid     Error error;
3903f57216cSOmair Javaid 
3913f57216cSOmair Javaid     if (!data_sp)
3923f57216cSOmair Javaid     {
3933f57216cSOmair Javaid         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
3943f57216cSOmair Javaid         return error;
3953f57216cSOmair Javaid     }
3963f57216cSOmair Javaid 
3973f57216cSOmair Javaid     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
3983f57216cSOmair Javaid     {
399bef47e49SGreg 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 ());
4003f57216cSOmair Javaid         return error;
4013f57216cSOmair Javaid     }
4023f57216cSOmair Javaid 
4033f57216cSOmair Javaid 
4043f57216cSOmair Javaid     uint8_t *src = data_sp->GetBytes ();
4053f57216cSOmair Javaid     if (src == nullptr)
4063f57216cSOmair Javaid     {
4073f57216cSOmair Javaid         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
4083f57216cSOmair Javaid         return error;
4093f57216cSOmair Javaid     }
4103f57216cSOmair Javaid     ::memcpy (&m_gpr_arm, src, GetRegisterInfoInterface ().GetGPRSize ());
4113f57216cSOmair Javaid 
412068f8a7eSTamas Berghammer     error = WriteGPR();
413068f8a7eSTamas Berghammer     if (error.Fail())
4143f57216cSOmair Javaid         return error;
4153f57216cSOmair Javaid 
4163f57216cSOmair Javaid     src += GetRegisterInfoInterface ().GetGPRSize ();
4173f57216cSOmair Javaid     ::memcpy (&m_fpr, src, sizeof(m_fpr));
4183f57216cSOmair Javaid 
419068f8a7eSTamas Berghammer     error = WriteFPR();
4203f57216cSOmair Javaid     if (error.Fail())
4213f57216cSOmair Javaid         return error;
4223f57216cSOmair Javaid 
4233f57216cSOmair Javaid     return error;
4243f57216cSOmair Javaid }
4253f57216cSOmair Javaid 
4263f57216cSOmair Javaid bool
4273f57216cSOmair Javaid NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const
4283f57216cSOmair Javaid {
4293f57216cSOmair Javaid     return reg <= m_reg_info.last_gpr;   // GPR's come first.
4303f57216cSOmair Javaid }
4313f57216cSOmair Javaid 
4323f57216cSOmair Javaid bool
4333f57216cSOmair Javaid NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const
4343f57216cSOmair Javaid {
4353f57216cSOmair Javaid     return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
4363f57216cSOmair Javaid }
4373f57216cSOmair Javaid 
4382441aecdSOmair Javaid uint32_t
4392441aecdSOmair Javaid NativeRegisterContextLinux_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
4402441aecdSOmair Javaid {
4412441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
4422441aecdSOmair Javaid 
4432441aecdSOmair Javaid     if (log)
4442441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
4452441aecdSOmair Javaid 
4462441aecdSOmair Javaid     Error error;
4472441aecdSOmair Javaid 
4482441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
4492441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
4502441aecdSOmair Javaid 
4512441aecdSOmair Javaid     if (error.Fail())
4522441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
4532441aecdSOmair Javaid 
4542441aecdSOmair Javaid     uint32_t control_value = 0, bp_index = 0;
4552441aecdSOmair Javaid 
4562441aecdSOmair Javaid     // Check if size has a valid hardware breakpoint length.
4572441aecdSOmair Javaid     // Thumb instructions are 2-bytes but we have no way here to determine
4582441aecdSOmair Javaid     // if target address is a thumb or arm instruction.
4592441aecdSOmair Javaid     // TODO: Add support for setting thumb mode hardware breakpoints
4602441aecdSOmair Javaid     if (size != 4 && size != 2)
4612441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
4622441aecdSOmair Javaid 
4632441aecdSOmair Javaid     // Setup control value
4642441aecdSOmair Javaid     // Make the byte_mask into a valid Byte Address Select mask
4652441aecdSOmair Javaid     control_value = 0xfu << 5;
4662441aecdSOmair Javaid 
4672441aecdSOmair Javaid     // Enable this breakpoint and make it stop in privileged or user mode;
4682441aecdSOmair Javaid     control_value |= 7;
4692441aecdSOmair Javaid 
4702441aecdSOmair Javaid     // Make sure bits 1:0 are clear in our address
4712441aecdSOmair Javaid     // This should be different once we support thumb here.
4722441aecdSOmair Javaid     addr &= ~((lldb::addr_t)3);
4732441aecdSOmair Javaid 
4742441aecdSOmair Javaid     // Iterate over stored hardware breakpoints
4752441aecdSOmair Javaid     // Find a free bp_index or update reference count if duplicate.
4762441aecdSOmair Javaid     bp_index = LLDB_INVALID_INDEX32;
4772441aecdSOmair Javaid 
4782441aecdSOmair Javaid     for (uint32_t i = 0; i < m_max_hbp_supported; i++)
4792441aecdSOmair Javaid     {
4802441aecdSOmair Javaid         if ((m_hbr_regs[i].control & 1) == 0)
4812441aecdSOmair Javaid         {
4822441aecdSOmair Javaid             bp_index = i;  // Mark last free slot
4832441aecdSOmair Javaid         }
4842441aecdSOmair Javaid         else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
4852441aecdSOmair Javaid         {
4862441aecdSOmair Javaid             bp_index = i;  // Mark duplicate index
4872441aecdSOmair Javaid             break;  // Stop searching here
4882441aecdSOmair Javaid         }
4892441aecdSOmair Javaid     }
4902441aecdSOmair Javaid 
4912441aecdSOmair Javaid      if (bp_index == LLDB_INVALID_INDEX32)
4922441aecdSOmair Javaid          return LLDB_INVALID_INDEX32;
4932441aecdSOmair Javaid 
4944aa984c1SOmair Javaid     // Add new or update existing breakpoint
4952441aecdSOmair Javaid     if ((m_hbr_regs[bp_index].control & 1) == 0)
4962441aecdSOmair Javaid     {
4972441aecdSOmair Javaid         m_hbr_regs[bp_index].address = addr;
4982441aecdSOmair Javaid         m_hbr_regs[bp_index].control = control_value;
4992441aecdSOmair Javaid         m_hbr_regs[bp_index].refcount = 1;
5002441aecdSOmair Javaid 
5012441aecdSOmair Javaid         // PTRACE call to set corresponding hardware breakpoint register.
5022441aecdSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
5032441aecdSOmair Javaid 
5042441aecdSOmair Javaid         if (error.Fail())
505d5510d1eSOmair Javaid         {
506d5510d1eSOmair Javaid             m_hbr_regs[bp_index].address = 0;
507d5510d1eSOmair Javaid             m_hbr_regs[bp_index].control &= ~1;
508d5510d1eSOmair Javaid             m_hbr_regs[bp_index].refcount = 0;
509d5510d1eSOmair Javaid 
5102441aecdSOmair Javaid             return LLDB_INVALID_INDEX32;
5112441aecdSOmair Javaid         }
512d5510d1eSOmair Javaid     }
5132441aecdSOmair Javaid     else
5142441aecdSOmair Javaid         m_hbr_regs[bp_index].refcount++;
5152441aecdSOmair Javaid 
5162441aecdSOmair Javaid     return bp_index;
5172441aecdSOmair Javaid }
5182441aecdSOmair Javaid 
5192441aecdSOmair Javaid bool
5202441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearHardwareBreakpoint (uint32_t hw_idx)
5212441aecdSOmair Javaid {
5222441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
5232441aecdSOmair Javaid 
5242441aecdSOmair Javaid     if (log)
5252441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
5262441aecdSOmair Javaid 
5272441aecdSOmair Javaid     Error error;
5282441aecdSOmair Javaid 
5292441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
5302441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
5312441aecdSOmair Javaid 
5322441aecdSOmair Javaid     if (error.Fail())
5334aa984c1SOmair Javaid         return false;
5342441aecdSOmair Javaid 
5352441aecdSOmair Javaid     if (hw_idx >= m_max_hbp_supported)
5362441aecdSOmair Javaid         return false;
5372441aecdSOmair Javaid 
5382441aecdSOmair Javaid     // Update reference count if multiple references.
5392441aecdSOmair Javaid     if (m_hbr_regs[hw_idx].refcount > 1)
5402441aecdSOmair Javaid     {
5412441aecdSOmair Javaid         m_hbr_regs[hw_idx].refcount--;
5422441aecdSOmair Javaid         return true;
5432441aecdSOmair Javaid     }
5442441aecdSOmair Javaid     else if (m_hbr_regs[hw_idx].refcount == 1)
5452441aecdSOmair Javaid     {
546d5510d1eSOmair Javaid         // Create a backup we can revert to in case of failure.
547d5510d1eSOmair Javaid         lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
548d5510d1eSOmair Javaid         uint32_t tempControl = m_hbr_regs[hw_idx].control;
549d5510d1eSOmair Javaid         uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount;
550d5510d1eSOmair Javaid 
5512441aecdSOmair Javaid         m_hbr_regs[hw_idx].control &= ~1;
5522441aecdSOmair Javaid         m_hbr_regs[hw_idx].address = 0;
5532441aecdSOmair Javaid         m_hbr_regs[hw_idx].refcount = 0;
5542441aecdSOmair Javaid 
5552441aecdSOmair Javaid         // PTRACE call to clear corresponding hardware breakpoint register.
5562441aecdSOmair Javaid         WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
5572441aecdSOmair Javaid 
5582441aecdSOmair Javaid         if (error.Fail())
559d5510d1eSOmair Javaid         {
560d5510d1eSOmair Javaid             m_hbr_regs[hw_idx].control = tempControl;
561d5510d1eSOmair Javaid             m_hbr_regs[hw_idx].address = tempAddr;
562d5510d1eSOmair Javaid             m_hbr_regs[hw_idx].refcount = tempRefCount;
563d5510d1eSOmair Javaid 
5644aa984c1SOmair Javaid             return false;
565d5510d1eSOmair Javaid         }
5662441aecdSOmair Javaid 
5672441aecdSOmair Javaid         return true;
5682441aecdSOmair Javaid     }
5692441aecdSOmair Javaid 
5702441aecdSOmair Javaid     return false;
5712441aecdSOmair Javaid }
5722441aecdSOmair Javaid 
5732441aecdSOmair Javaid uint32_t
5742441aecdSOmair Javaid NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints ()
5752441aecdSOmair Javaid {
5762441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
5772441aecdSOmair Javaid 
5782441aecdSOmair Javaid     if (log)
5792441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
5802441aecdSOmair Javaid 
5812441aecdSOmair Javaid     Error error;
5822441aecdSOmair Javaid 
5832441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
5842441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
5852441aecdSOmair Javaid 
5862441aecdSOmair Javaid     if (error.Fail())
5872441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
5882441aecdSOmair Javaid 
5892441aecdSOmair Javaid     return m_max_hwp_supported;
5902441aecdSOmair Javaid }
5912441aecdSOmair Javaid 
5922441aecdSOmair Javaid uint32_t
5932441aecdSOmair Javaid NativeRegisterContextLinux_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
5942441aecdSOmair Javaid {
5952441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
5962441aecdSOmair Javaid 
5972441aecdSOmair Javaid     if (log)
5982441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
5992441aecdSOmair Javaid 
6002441aecdSOmair Javaid     Error error;
6012441aecdSOmair Javaid 
6022441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
6032441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
6042441aecdSOmair Javaid 
6052441aecdSOmair Javaid     if (error.Fail())
6062441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
6072441aecdSOmair Javaid 
6082441aecdSOmair Javaid     uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
6092441aecdSOmair Javaid 
6102441aecdSOmair Javaid     // Check if we are setting watchpoint other than read/write/access
6112441aecdSOmair Javaid     // Also update watchpoint flag to match Arm write-read bit configuration.
6122441aecdSOmair Javaid     switch (watch_flags)
6132441aecdSOmair Javaid     {
6142441aecdSOmair Javaid         case 1:
6152441aecdSOmair Javaid             watch_flags = 2;
6162441aecdSOmair Javaid             break;
6172441aecdSOmair Javaid         case 2:
6182441aecdSOmair Javaid             watch_flags = 1;
6192441aecdSOmair Javaid             break;
6202441aecdSOmair Javaid         case 3:
6212441aecdSOmair Javaid             break;
6222441aecdSOmair Javaid         default:
6232441aecdSOmair Javaid             return LLDB_INVALID_INDEX32;
6242441aecdSOmair Javaid     }
6252441aecdSOmair Javaid 
6262441aecdSOmair Javaid     // Can't watch zero bytes
6272441aecdSOmair Javaid     // Can't watch more than 4 bytes per WVR/WCR pair
6282441aecdSOmair Javaid 
6292441aecdSOmair Javaid     if (size == 0 || size > 4)
6302441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
6312441aecdSOmair Javaid 
6322441aecdSOmair Javaid     // We can only watch up to four bytes that follow a 4 byte aligned address
6332441aecdSOmair Javaid     // per watchpoint register pair, so make sure we can properly encode this.
6342441aecdSOmair Javaid     addr_word_offset = addr % 4;
6352441aecdSOmair Javaid     byte_mask = ((1u << size) - 1u) << addr_word_offset;
6362441aecdSOmair Javaid 
6372441aecdSOmair Javaid     // Check if we need multiple watchpoint register
6382441aecdSOmair Javaid     if (byte_mask > 0xfu)
6392441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
6402441aecdSOmair Javaid 
6412441aecdSOmair Javaid     // Setup control value
6422441aecdSOmair Javaid     // Make the byte_mask into a valid Byte Address Select mask
6432441aecdSOmair Javaid     control_value = byte_mask << 5;
6442441aecdSOmair Javaid 
6452441aecdSOmair Javaid     //Turn on appropriate watchpoint flags read or write
6462441aecdSOmair Javaid     control_value |= (watch_flags << 3);
6472441aecdSOmair Javaid 
6482441aecdSOmair Javaid     // Enable this watchpoint and make it stop in privileged or user mode;
6492441aecdSOmair Javaid     control_value |= 7;
6502441aecdSOmair Javaid 
6512441aecdSOmair Javaid     // Make sure bits 1:0 are clear in our address
6522441aecdSOmair Javaid     addr &= ~((lldb::addr_t)3);
6532441aecdSOmair Javaid 
6542441aecdSOmair Javaid     // Iterate over stored watchpoints
6552441aecdSOmair Javaid     // Find a free wp_index or update reference count if duplicate.
6562441aecdSOmair Javaid     wp_index = LLDB_INVALID_INDEX32;
6572441aecdSOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
6582441aecdSOmair Javaid     {
6592441aecdSOmair Javaid         if ((m_hwp_regs[i].control & 1) == 0)
6602441aecdSOmair Javaid         {
6612441aecdSOmair Javaid             wp_index = i; // Mark last free slot
6622441aecdSOmair Javaid         }
6632441aecdSOmair Javaid         else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
6642441aecdSOmair Javaid         {
6652441aecdSOmair Javaid             wp_index = i; // Mark duplicate index
6662441aecdSOmair Javaid             break; // Stop searching here
6672441aecdSOmair Javaid         }
6682441aecdSOmair Javaid     }
6692441aecdSOmair Javaid 
6702441aecdSOmair Javaid      if (wp_index == LLDB_INVALID_INDEX32)
6712441aecdSOmair Javaid         return LLDB_INVALID_INDEX32;
6722441aecdSOmair Javaid 
6732441aecdSOmair Javaid     // Add new or update existing watchpoint
6742441aecdSOmair Javaid     if ((m_hwp_regs[wp_index].control & 1) == 0)
6752441aecdSOmair Javaid     {
6762441aecdSOmair Javaid         // Update watchpoint in local cache
6772441aecdSOmair Javaid         m_hwp_regs[wp_index].address = addr;
6782441aecdSOmair Javaid         m_hwp_regs[wp_index].control = control_value;
6792441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount = 1;
6802441aecdSOmair Javaid 
6812441aecdSOmair Javaid         // PTRACE call to set corresponding watchpoint register.
6822441aecdSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
6832441aecdSOmair Javaid 
6842441aecdSOmair Javaid         if (error.Fail())
685d5510d1eSOmair Javaid         {
686d5510d1eSOmair Javaid             m_hwp_regs[wp_index].address = 0;
687d5510d1eSOmair Javaid             m_hwp_regs[wp_index].control &= ~1;
688d5510d1eSOmair Javaid             m_hwp_regs[wp_index].refcount = 0;
689d5510d1eSOmair Javaid 
6902441aecdSOmair Javaid             return LLDB_INVALID_INDEX32;
6912441aecdSOmair Javaid         }
692d5510d1eSOmair Javaid     }
6932441aecdSOmair Javaid     else
6942441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount++;
6952441aecdSOmair Javaid 
6962441aecdSOmair Javaid     return wp_index;
6972441aecdSOmair Javaid }
6982441aecdSOmair Javaid 
6992441aecdSOmair Javaid bool
7002441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearHardwareWatchpoint (uint32_t wp_index)
7012441aecdSOmair Javaid {
7022441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
7032441aecdSOmair Javaid 
7042441aecdSOmair Javaid     if (log)
7052441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7062441aecdSOmair Javaid 
7072441aecdSOmair Javaid     Error error;
7082441aecdSOmair Javaid 
7092441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
7102441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
7112441aecdSOmair Javaid 
7122441aecdSOmair Javaid     if (error.Fail())
7134aa984c1SOmair Javaid         return false;
7142441aecdSOmair Javaid 
7152441aecdSOmair Javaid     if (wp_index >= m_max_hwp_supported)
7162441aecdSOmair Javaid         return false;
7172441aecdSOmair Javaid 
7182441aecdSOmair Javaid     // Update reference count if multiple references.
7192441aecdSOmair Javaid     if (m_hwp_regs[wp_index].refcount > 1)
7202441aecdSOmair Javaid     {
7212441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount--;
7222441aecdSOmair Javaid         return true;
7232441aecdSOmair Javaid     }
7242441aecdSOmair Javaid     else if (m_hwp_regs[wp_index].refcount == 1)
7252441aecdSOmair Javaid     {
726d5510d1eSOmair Javaid         // Create a backup we can revert to in case of failure.
727d5510d1eSOmair Javaid         lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
728d5510d1eSOmair Javaid         uint32_t tempControl = m_hwp_regs[wp_index].control;
729d5510d1eSOmair Javaid         uint32_t tempRefCount = m_hwp_regs[wp_index].refcount;
730d5510d1eSOmair Javaid 
7312441aecdSOmair Javaid         // Update watchpoint in local cache
7322441aecdSOmair Javaid         m_hwp_regs[wp_index].control &= ~1;
7332441aecdSOmair Javaid         m_hwp_regs[wp_index].address = 0;
7342441aecdSOmair Javaid         m_hwp_regs[wp_index].refcount = 0;
7352441aecdSOmair Javaid 
7362441aecdSOmair Javaid         // Ptrace call to update hardware debug registers
7372441aecdSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
7382441aecdSOmair Javaid 
7392441aecdSOmair Javaid         if (error.Fail())
740d5510d1eSOmair Javaid         {
741d5510d1eSOmair Javaid             m_hwp_regs[wp_index].control = tempControl;
742d5510d1eSOmair Javaid             m_hwp_regs[wp_index].address = tempAddr;
743d5510d1eSOmair Javaid             m_hwp_regs[wp_index].refcount = tempRefCount;
744d5510d1eSOmair Javaid 
7452441aecdSOmair Javaid             return false;
746d5510d1eSOmair Javaid         }
7472441aecdSOmair Javaid 
7482441aecdSOmair Javaid         return true;
7492441aecdSOmair Javaid     }
7502441aecdSOmair Javaid 
7512441aecdSOmair Javaid     return false;
7522441aecdSOmair Javaid }
7532441aecdSOmair Javaid 
7542441aecdSOmair Javaid Error
7552441aecdSOmair Javaid NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints ()
7562441aecdSOmair Javaid {
7572441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
7582441aecdSOmair Javaid 
7592441aecdSOmair Javaid     if (log)
7602441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7612441aecdSOmair Javaid 
7622441aecdSOmair Javaid     Error error;
7632441aecdSOmair Javaid 
7642441aecdSOmair Javaid     // Read hardware breakpoint and watchpoint information.
7652441aecdSOmair Javaid     error = ReadHardwareDebugInfo ();
7662441aecdSOmair Javaid 
7672441aecdSOmair Javaid     if (error.Fail())
7682441aecdSOmair Javaid         return error;
7692441aecdSOmair Javaid 
770d5510d1eSOmair Javaid     lldb::addr_t tempAddr = 0;
771d5510d1eSOmair Javaid     uint32_t tempControl = 0, tempRefCount = 0;
772d5510d1eSOmair Javaid 
7732441aecdSOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
7742441aecdSOmair Javaid     {
7752441aecdSOmair Javaid         if (m_hwp_regs[i].control & 0x01)
7762441aecdSOmair Javaid         {
777d5510d1eSOmair Javaid             // Create a backup we can revert to in case of failure.
778d5510d1eSOmair Javaid             tempAddr = m_hwp_regs[i].address;
779d5510d1eSOmair Javaid             tempControl = m_hwp_regs[i].control;
780d5510d1eSOmair Javaid             tempRefCount = m_hwp_regs[i].refcount;
781d5510d1eSOmair Javaid 
7822441aecdSOmair Javaid             // Clear watchpoints in local cache
7832441aecdSOmair Javaid             m_hwp_regs[i].control &= ~1;
7842441aecdSOmair Javaid             m_hwp_regs[i].address = 0;
7852441aecdSOmair Javaid             m_hwp_regs[i].refcount = 0;
7862441aecdSOmair Javaid 
7872441aecdSOmair Javaid             // Ptrace call to update hardware debug registers
7882441aecdSOmair Javaid             error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
7892441aecdSOmair Javaid 
7902441aecdSOmair Javaid             if (error.Fail())
791d5510d1eSOmair Javaid             {
792d5510d1eSOmair Javaid                 m_hwp_regs[i].control = tempControl;
793d5510d1eSOmair Javaid                 m_hwp_regs[i].address = tempAddr;
794d5510d1eSOmair Javaid                 m_hwp_regs[i].refcount = tempRefCount;
795d5510d1eSOmair Javaid 
7962441aecdSOmair Javaid                 return error;
7972441aecdSOmair Javaid             }
7982441aecdSOmair Javaid         }
799d5510d1eSOmair Javaid     }
8002441aecdSOmair Javaid 
8012441aecdSOmair Javaid     return Error();
8022441aecdSOmair Javaid }
8032441aecdSOmair Javaid 
8042441aecdSOmair Javaid uint32_t
8052441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index)
8062441aecdSOmair Javaid {
8072441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
8082441aecdSOmair Javaid 
8092441aecdSOmair Javaid     if (log)
8102441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
8112441aecdSOmair Javaid 
8122441aecdSOmair Javaid     switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f)
8132441aecdSOmair Javaid     {
8142441aecdSOmair Javaid         case 0x01:
8152441aecdSOmair Javaid             return 1;
8162441aecdSOmair Javaid         case 0x03:
8172441aecdSOmair Javaid             return 2;
8182441aecdSOmair Javaid         case 0x07:
8192441aecdSOmair Javaid             return 3;
8202441aecdSOmair Javaid         case 0x0f:
8212441aecdSOmair Javaid             return 4;
8222441aecdSOmair Javaid         default:
8232441aecdSOmair Javaid             return 0;
8242441aecdSOmair Javaid     }
8252441aecdSOmair Javaid }
8262441aecdSOmair Javaid bool
8272441aecdSOmair Javaid NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index)
8282441aecdSOmair Javaid {
8292441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
8302441aecdSOmair Javaid 
8312441aecdSOmair Javaid     if (log)
8322441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
8332441aecdSOmair Javaid 
8342441aecdSOmair Javaid     if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
8352441aecdSOmair Javaid         return true;
8362441aecdSOmair Javaid     else
8372441aecdSOmair Javaid         return false;
8382441aecdSOmair Javaid }
8392441aecdSOmair Javaid 
8402441aecdSOmair Javaid Error
8412441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
8422441aecdSOmair Javaid {
8432441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
8442441aecdSOmair Javaid 
8452441aecdSOmair Javaid     if (log)
8462441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
8472441aecdSOmair Javaid 
8482441aecdSOmair Javaid     uint32_t watch_size;
8492441aecdSOmair Javaid     lldb::addr_t watch_addr;
8502441aecdSOmair Javaid 
8512441aecdSOmair Javaid     for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
8522441aecdSOmair Javaid     {
8532441aecdSOmair Javaid         watch_size = GetWatchpointSize (wp_index);
8542441aecdSOmair Javaid         watch_addr = m_hwp_regs[wp_index].address;
8552441aecdSOmair Javaid 
8562441aecdSOmair Javaid         if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
8572441aecdSOmair Javaid             && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
8582441aecdSOmair Javaid         {
8592441aecdSOmair Javaid             return Error();
8602441aecdSOmair Javaid         }
8612441aecdSOmair Javaid     }
8622441aecdSOmair Javaid 
8632441aecdSOmair Javaid     wp_index = LLDB_INVALID_INDEX32;
8642441aecdSOmair Javaid     return Error();
8652441aecdSOmair Javaid }
8662441aecdSOmair Javaid 
8672441aecdSOmair Javaid lldb::addr_t
8682441aecdSOmair Javaid NativeRegisterContextLinux_arm::GetWatchpointAddress (uint32_t wp_index)
8692441aecdSOmair Javaid {
8702441aecdSOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
8712441aecdSOmair Javaid 
8722441aecdSOmair Javaid     if (log)
8732441aecdSOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
8742441aecdSOmair Javaid 
8752441aecdSOmair Javaid     if (wp_index >= m_max_hwp_supported)
8762441aecdSOmair Javaid         return LLDB_INVALID_ADDRESS;
8772441aecdSOmair Javaid 
8782441aecdSOmair Javaid     if (WatchpointIsEnabled(wp_index))
8792441aecdSOmair Javaid         return m_hwp_regs[wp_index].address;
8802441aecdSOmair Javaid     else
8812441aecdSOmair Javaid         return LLDB_INVALID_ADDRESS;
8822441aecdSOmair Javaid }
8832441aecdSOmair Javaid 
8842441aecdSOmair Javaid Error
8852441aecdSOmair Javaid NativeRegisterContextLinux_arm::ReadHardwareDebugInfo()
8862441aecdSOmair Javaid {
8872441aecdSOmair Javaid     Error error;
8882441aecdSOmair Javaid 
8892441aecdSOmair Javaid     if (!m_refresh_hwdebug_info)
8902441aecdSOmair Javaid     {
8912441aecdSOmair Javaid         return Error();
8922441aecdSOmair Javaid     }
8932441aecdSOmair Javaid 
8942441aecdSOmair Javaid     unsigned int cap_val;
8952441aecdSOmair Javaid 
8962441aecdSOmair Javaid     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), nullptr, &cap_val, sizeof(unsigned int));
8972441aecdSOmair Javaid 
8982441aecdSOmair Javaid     if (error.Fail())
8992441aecdSOmair Javaid         return error;
9002441aecdSOmair Javaid 
9012441aecdSOmair Javaid     m_max_hwp_supported = (cap_val >> 8) & 0xff;
9022441aecdSOmair Javaid     m_max_hbp_supported = cap_val & 0xff;
9032441aecdSOmair Javaid     m_refresh_hwdebug_info = false;
9042441aecdSOmair Javaid 
9052441aecdSOmair Javaid     return error;
9062441aecdSOmair Javaid }
9072441aecdSOmair Javaid 
9082441aecdSOmair Javaid Error
9092441aecdSOmair Javaid NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, int hwb_index)
9102441aecdSOmair Javaid {
9112441aecdSOmair Javaid     Error error;
9122441aecdSOmair Javaid 
9132441aecdSOmair Javaid     lldb::addr_t *addr_buf;
9142441aecdSOmair Javaid     uint32_t *ctrl_buf;
9152441aecdSOmair Javaid 
9162441aecdSOmair Javaid     if (hwbType == eDREGTypeWATCH)
9172441aecdSOmair Javaid     {
9182441aecdSOmair Javaid         addr_buf = &m_hwp_regs[hwb_index].address;
9192441aecdSOmair Javaid         ctrl_buf = &m_hwp_regs[hwb_index].control;
9202441aecdSOmair Javaid 
9212441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
9222441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 1),
9232441aecdSOmair Javaid                 addr_buf, sizeof(unsigned int));
9242441aecdSOmair Javaid 
9252441aecdSOmair Javaid         if (error.Fail())
9262441aecdSOmair Javaid             return error;
9272441aecdSOmair Javaid 
9282441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
9292441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 2),
9302441aecdSOmair Javaid                 ctrl_buf, sizeof(unsigned int));
9312441aecdSOmair Javaid     }
9322441aecdSOmair Javaid     else
9332441aecdSOmair Javaid     {
9342441aecdSOmair Javaid         addr_buf = &m_hwp_regs[hwb_index].address;
9352441aecdSOmair Javaid         ctrl_buf = &m_hwp_regs[hwb_index].control;
9362441aecdSOmair Javaid 
9372441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
9382441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 1),
9392441aecdSOmair Javaid                 addr_buf, sizeof(unsigned int));
9402441aecdSOmair Javaid 
9412441aecdSOmair Javaid         if (error.Fail())
9422441aecdSOmair Javaid             return error;
9432441aecdSOmair Javaid 
9442441aecdSOmair Javaid         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
9452441aecdSOmair Javaid                 m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 2),
9462441aecdSOmair Javaid                 ctrl_buf, sizeof(unsigned int));
9472441aecdSOmair Javaid 
9482441aecdSOmair Javaid     }
9492441aecdSOmair Javaid 
9502441aecdSOmair Javaid     return error;
9512441aecdSOmair Javaid }
952c40e7b17STamas Berghammer 
953c40e7b17STamas Berghammer uint32_t
954c40e7b17STamas Berghammer NativeRegisterContextLinux_arm::CalculateFprOffset(const RegisterInfo* reg_info) const
955c40e7b17STamas Berghammer {
956c40e7b17STamas Berghammer     return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
957c40e7b17STamas Berghammer }
958c40e7b17STamas Berghammer 
959ce26b7a6STamas Berghammer Error
960ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoWriteRegisterValue(uint32_t offset,
961ce26b7a6STamas Berghammer                                                      const char* reg_name,
962ce26b7a6STamas Berghammer                                                      const RegisterValue &value)
963ce26b7a6STamas Berghammer {
964ce26b7a6STamas Berghammer     // PTRACE_POKEUSER don't work in the aarch64 liux kernel used on android devices (always return
965ce26b7a6STamas Berghammer     // "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR register set, modify
966ce26b7a6STamas Berghammer     // the requested register and write it back. This approach is about 4 times slower but the
967ce26b7a6STamas Berghammer     // performance overhead is negligible in comparision to processing time in lldb-server.
968ce26b7a6STamas Berghammer     assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
969ce26b7a6STamas Berghammer     if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
970ce26b7a6STamas Berghammer         return Error("Register isn't fit into the size of the GPR area");
971ce26b7a6STamas Berghammer 
972ce26b7a6STamas Berghammer     Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm));
973ce26b7a6STamas Berghammer     if (error.Fail())
974ce26b7a6STamas Berghammer         return error;
975ce26b7a6STamas Berghammer 
976*a7d7f7cfSOmair Javaid     uint32_t reg_value = value.GetAsUInt32();
977*a7d7f7cfSOmair Javaid     // As precaution for an undefined behavior encountered while setting PC we
978*a7d7f7cfSOmair Javaid     // will clear thumb bit of new PC if we are already in thumb mode; that is
979*a7d7f7cfSOmair Javaid     // CPSR thumb mode bit is set.
980*a7d7f7cfSOmair Javaid     if (offset / sizeof(uint32_t) == gpr_pc_arm)
981*a7d7f7cfSOmair Javaid     {
982*a7d7f7cfSOmair Javaid         // Check if we are already in thumb mode and
983*a7d7f7cfSOmair Javaid         // thumb bit of current PC is read out to be zero and
984*a7d7f7cfSOmair Javaid         // thumb bit of next PC is read out to be one.
985*a7d7f7cfSOmair Javaid         if ((m_gpr_arm[gpr_cpsr_arm] &  0x20) &&
986*a7d7f7cfSOmair Javaid             !(m_gpr_arm[gpr_pc_arm] &  0x01) &&
987*a7d7f7cfSOmair Javaid             (value.GetAsUInt32() & 0x01))
988*a7d7f7cfSOmair Javaid         {
989*a7d7f7cfSOmair Javaid             reg_value &= (~1ull);
990*a7d7f7cfSOmair Javaid         }
991*a7d7f7cfSOmair Javaid     }
992*a7d7f7cfSOmair Javaid 
993*a7d7f7cfSOmair Javaid     m_gpr_arm[offset / sizeof(uint32_t)] = reg_value;
994ce26b7a6STamas Berghammer     return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm));
995ce26b7a6STamas Berghammer }
996ce26b7a6STamas Berghammer 
997ce26b7a6STamas Berghammer Error
998ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size)
999ce26b7a6STamas Berghammer {
1000ce26b7a6STamas Berghammer     return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS,
1001ce26b7a6STamas Berghammer                                              m_thread.GetID(),
1002ce26b7a6STamas Berghammer                                              nullptr,
1003ce26b7a6STamas Berghammer                                              buf,
1004ce26b7a6STamas Berghammer                                              buf_size);
1005ce26b7a6STamas Berghammer }
1006ce26b7a6STamas Berghammer 
1007ce26b7a6STamas Berghammer Error
1008ce26b7a6STamas Berghammer NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size)
1009ce26b7a6STamas Berghammer {
1010ce26b7a6STamas Berghammer     return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS,
1011ce26b7a6STamas Berghammer                                              m_thread.GetID(),
1012ce26b7a6STamas Berghammer                                              nullptr,
1013ce26b7a6STamas Berghammer                                              buf,
1014ce26b7a6STamas Berghammer                                              buf_size);
1015ce26b7a6STamas Berghammer }
1016ce26b7a6STamas Berghammer 
1017068f8a7eSTamas Berghammer #endif // defined(__arm__)
1018