13f57216cSOmair Javaid //===-- NativeRegisterContextLinux_arm.cpp --------------------*- C++ -*-===//
23f57216cSOmair Javaid //
33f57216cSOmair Javaid //                     The LLVM Compiler Infrastructure
43f57216cSOmair Javaid //
53f57216cSOmair Javaid // This file is distributed under the University of Illinois Open Source
63f57216cSOmair Javaid // License. See LICENSE.TXT for details.
73f57216cSOmair Javaid //
83f57216cSOmair Javaid //===----------------------------------------------------------------------===//
93f57216cSOmair Javaid 
10e85e6021STamas Berghammer #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
11068f8a7eSTamas Berghammer 
123f57216cSOmair Javaid #include "NativeRegisterContextLinux_arm.h"
133f57216cSOmair Javaid 
143f57216cSOmair Javaid #include "lldb/Core/DataBufferHeap.h"
153f57216cSOmair Javaid #include "lldb/Core/Error.h"
162441aecdSOmair Javaid #include "lldb/Core/Log.h"
173f57216cSOmair Javaid #include "lldb/Core/RegisterValue.h"
18068f8a7eSTamas Berghammer 
19e85e6021STamas Berghammer #include "Plugins/Process/Linux/Procfs.h"
20068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
213f57216cSOmair Javaid 
22e85e6021STamas Berghammer #include <elf.h>
23e85e6021STamas Berghammer #include <sys/socket.h>
24e85e6021STamas Berghammer 
253f57216cSOmair Javaid #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr))
263f57216cSOmair Javaid 
27ce26b7a6STamas Berghammer #ifndef PTRACE_GETVFPREGS
28ce26b7a6STamas Berghammer #define PTRACE_GETVFPREGS 27
29ce26b7a6STamas Berghammer #define PTRACE_SETVFPREGS 28
30ce26b7a6STamas Berghammer #endif
312441aecdSOmair Javaid #ifndef PTRACE_GETHBPREGS
322441aecdSOmair Javaid #define PTRACE_GETHBPREGS 29
332441aecdSOmair Javaid #define PTRACE_SETHBPREGS 30
342441aecdSOmair Javaid #endif
352441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG3)
362441aecdSOmair Javaid #define PTRACE_TYPE_ARG3 void *
372441aecdSOmair Javaid #endif
382441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG4)
392441aecdSOmair Javaid #define PTRACE_TYPE_ARG4 void *
402441aecdSOmair Javaid #endif
412441aecdSOmair Javaid 
423f57216cSOmair Javaid using namespace lldb;
433f57216cSOmair Javaid using namespace lldb_private;
443f57216cSOmair Javaid using namespace lldb_private::process_linux;
453f57216cSOmair Javaid 
463f57216cSOmair Javaid // arm general purpose registers.
47*b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_arm[] = {
48*b9c1b51eSKate Stone     gpr_r0_arm,         gpr_r1_arm,   gpr_r2_arm,  gpr_r3_arm, gpr_r4_arm,
49*b9c1b51eSKate Stone     gpr_r5_arm,         gpr_r6_arm,   gpr_r7_arm,  gpr_r8_arm, gpr_r9_arm,
50*b9c1b51eSKate Stone     gpr_r10_arm,        gpr_r11_arm,  gpr_r12_arm, gpr_sp_arm, gpr_lr_arm,
51*b9c1b51eSKate Stone     gpr_pc_arm,         gpr_cpsr_arm,
523f57216cSOmair Javaid     LLDB_INVALID_REGNUM // register sets need to end with this flag
533f57216cSOmair Javaid };
54*b9c1b51eSKate Stone static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) ==
55*b9c1b51eSKate Stone                   k_num_gpr_registers_arm,
563f57216cSOmair Javaid               "g_gpr_regnums_arm has wrong number of register infos");
573f57216cSOmair Javaid 
583f57216cSOmair Javaid // arm floating point registers.
59*b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_arm[] = {
60*b9c1b51eSKate Stone     fpu_s0_arm,         fpu_s1_arm,  fpu_s2_arm,    fpu_s3_arm,  fpu_s4_arm,
61*b9c1b51eSKate Stone     fpu_s5_arm,         fpu_s6_arm,  fpu_s7_arm,    fpu_s8_arm,  fpu_s9_arm,
62*b9c1b51eSKate Stone     fpu_s10_arm,        fpu_s11_arm, fpu_s12_arm,   fpu_s13_arm, fpu_s14_arm,
63*b9c1b51eSKate Stone     fpu_s15_arm,        fpu_s16_arm, fpu_s17_arm,   fpu_s18_arm, fpu_s19_arm,
64*b9c1b51eSKate Stone     fpu_s20_arm,        fpu_s21_arm, fpu_s22_arm,   fpu_s23_arm, fpu_s24_arm,
65*b9c1b51eSKate Stone     fpu_s25_arm,        fpu_s26_arm, fpu_s27_arm,   fpu_s28_arm, fpu_s29_arm,
66*b9c1b51eSKate Stone     fpu_s30_arm,        fpu_s31_arm, fpu_fpscr_arm, fpu_d0_arm,  fpu_d1_arm,
67*b9c1b51eSKate Stone     fpu_d2_arm,         fpu_d3_arm,  fpu_d4_arm,    fpu_d5_arm,  fpu_d6_arm,
68*b9c1b51eSKate Stone     fpu_d7_arm,         fpu_d8_arm,  fpu_d9_arm,    fpu_d10_arm, fpu_d11_arm,
69*b9c1b51eSKate Stone     fpu_d12_arm,        fpu_d13_arm, fpu_d14_arm,   fpu_d15_arm, fpu_d16_arm,
70*b9c1b51eSKate Stone     fpu_d17_arm,        fpu_d18_arm, fpu_d19_arm,   fpu_d20_arm, fpu_d21_arm,
71*b9c1b51eSKate Stone     fpu_d22_arm,        fpu_d23_arm, fpu_d24_arm,   fpu_d25_arm, fpu_d26_arm,
72*b9c1b51eSKate Stone     fpu_d27_arm,        fpu_d28_arm, fpu_d29_arm,   fpu_d30_arm, fpu_d31_arm,
73*b9c1b51eSKate Stone     fpu_q0_arm,         fpu_q1_arm,  fpu_q2_arm,    fpu_q3_arm,  fpu_q4_arm,
74*b9c1b51eSKate Stone     fpu_q5_arm,         fpu_q6_arm,  fpu_q7_arm,    fpu_q8_arm,  fpu_q9_arm,
75*b9c1b51eSKate Stone     fpu_q10_arm,        fpu_q11_arm, fpu_q12_arm,   fpu_q13_arm, fpu_q14_arm,
76b4e95a50STamas Berghammer     fpu_q15_arm,
773f57216cSOmair Javaid     LLDB_INVALID_REGNUM // register sets need to end with this flag
783f57216cSOmair Javaid };
79*b9c1b51eSKate Stone static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) ==
80*b9c1b51eSKate Stone                   k_num_fpr_registers_arm,
813f57216cSOmair Javaid               "g_fpu_regnums_arm has wrong number of register infos");
823f57216cSOmair Javaid 
833f57216cSOmair Javaid namespace {
843f57216cSOmair Javaid // Number of register sets provided by this context.
85*b9c1b51eSKate Stone enum { k_num_register_sets = 2 };
863f57216cSOmair Javaid }
873f57216cSOmair Javaid 
883f57216cSOmair Javaid // Register sets for arm.
89*b9c1b51eSKate Stone static const RegisterSet g_reg_sets_arm[k_num_register_sets] = {
90*b9c1b51eSKate Stone     {"General Purpose Registers", "gpr", k_num_gpr_registers_arm,
91*b9c1b51eSKate Stone      g_gpr_regnums_arm},
92*b9c1b51eSKate Stone     {"Floating Point Registers", "fpu", k_num_fpr_registers_arm,
93*b9c1b51eSKate Stone      g_fpu_regnums_arm}};
943f57216cSOmair Javaid 
95e85e6021STamas Berghammer #if defined(__arm__)
96e85e6021STamas Berghammer 
97068f8a7eSTamas Berghammer NativeRegisterContextLinux *
98*b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
99*b9c1b51eSKate Stone     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
100*b9c1b51eSKate Stone     uint32_t concrete_frame_idx) {
101*b9c1b51eSKate Stone   return new NativeRegisterContextLinux_arm(target_arch, native_thread,
102*b9c1b51eSKate Stone                                             concrete_frame_idx);
103068f8a7eSTamas Berghammer }
104068f8a7eSTamas Berghammer 
105e85e6021STamas Berghammer #endif // defined(__arm__)
106e85e6021STamas Berghammer 
107*b9c1b51eSKate Stone NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
108*b9c1b51eSKate Stone     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
109*b9c1b51eSKate Stone     uint32_t concrete_frame_idx)
110*b9c1b51eSKate Stone     : NativeRegisterContextLinux(native_thread, concrete_frame_idx,
111*b9c1b51eSKate Stone                                  new RegisterContextLinux_arm(target_arch)) {
112*b9c1b51eSKate Stone   switch (target_arch.GetMachine()) {
1133f57216cSOmair Javaid   case llvm::Triple::arm:
1143f57216cSOmair Javaid     m_reg_info.num_registers = k_num_registers_arm;
1153f57216cSOmair Javaid     m_reg_info.num_gpr_registers = k_num_gpr_registers_arm;
1163f57216cSOmair Javaid     m_reg_info.num_fpr_registers = k_num_fpr_registers_arm;
1173f57216cSOmair Javaid     m_reg_info.last_gpr = k_last_gpr_arm;
1183f57216cSOmair Javaid     m_reg_info.first_fpr = k_first_fpr_arm;
1193f57216cSOmair Javaid     m_reg_info.last_fpr = k_last_fpr_arm;
1203f57216cSOmair Javaid     m_reg_info.first_fpr_v = fpu_s0_arm;
1213f57216cSOmair Javaid     m_reg_info.last_fpr_v = fpu_s31_arm;
1223f57216cSOmair Javaid     m_reg_info.gpr_flags = gpr_cpsr_arm;
1233f57216cSOmair Javaid     break;
1243f57216cSOmair Javaid   default:
1253f57216cSOmair Javaid     assert(false && "Unhandled target architecture.");
1263f57216cSOmair Javaid     break;
1273f57216cSOmair Javaid   }
1283f57216cSOmair Javaid 
1293f57216cSOmair Javaid   ::memset(&m_fpr, 0, sizeof(m_fpr));
1303f57216cSOmair Javaid   ::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm));
1312441aecdSOmair Javaid   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
1322441aecdSOmair Javaid 
1332441aecdSOmair Javaid   // 16 is just a maximum value, query hardware for actual watchpoint count
1342441aecdSOmair Javaid   m_max_hwp_supported = 16;
1352441aecdSOmair Javaid   m_max_hbp_supported = 16;
1362441aecdSOmair Javaid   m_refresh_hwdebug_info = true;
1373f57216cSOmair Javaid }
1383f57216cSOmair Javaid 
139*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount() const {
1403f57216cSOmair Javaid   return k_num_register_sets;
1413f57216cSOmair Javaid }
1423f57216cSOmair Javaid 
143*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount() const {
1441f149204STamas Berghammer   uint32_t count = 0;
1451f149204STamas Berghammer   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
1461f149204STamas Berghammer     count += g_reg_sets_arm[set_index].num_registers;
1471f149204STamas Berghammer   return count;
1481f149204STamas Berghammer }
1491f149204STamas Berghammer 
1503f57216cSOmair Javaid const RegisterSet *
151*b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index) const {
1523f57216cSOmair Javaid   if (set_index < k_num_register_sets)
1533f57216cSOmair Javaid     return &g_reg_sets_arm[set_index];
1543f57216cSOmair Javaid 
1553f57216cSOmair Javaid   return nullptr;
1563f57216cSOmair Javaid }
1573f57216cSOmair Javaid 
158*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ReadRegister(const RegisterInfo *reg_info,
159*b9c1b51eSKate Stone                                                    RegisterValue &reg_value) {
1603f57216cSOmair Javaid   Error error;
1613f57216cSOmair Javaid 
162*b9c1b51eSKate Stone   if (!reg_info) {
1633f57216cSOmair Javaid     error.SetErrorString("reg_info NULL");
1643f57216cSOmair Javaid     return error;
1653f57216cSOmair Javaid   }
1663f57216cSOmair Javaid 
1673f57216cSOmair Javaid   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
1683f57216cSOmair Javaid 
169*b9c1b51eSKate Stone   if (IsFPR(reg)) {
170068f8a7eSTamas Berghammer     error = ReadFPR();
171068f8a7eSTamas Berghammer     if (error.Fail())
1723f57216cSOmair Javaid       return error;
173*b9c1b51eSKate Stone   } else {
1743f57216cSOmair Javaid     uint32_t full_reg = reg;
175*b9c1b51eSKate Stone     bool is_subreg = reg_info->invalidate_regs &&
176*b9c1b51eSKate Stone                      (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
1773f57216cSOmair Javaid 
178*b9c1b51eSKate Stone     if (is_subreg) {
1793f57216cSOmair Javaid       // Read the full aligned 64-bit register.
1803f57216cSOmair Javaid       full_reg = reg_info->invalidate_regs[0];
1813f57216cSOmair Javaid     }
1823f57216cSOmair Javaid 
1833f57216cSOmair Javaid     error = ReadRegisterRaw(full_reg, reg_value);
1843f57216cSOmair Javaid 
185*b9c1b51eSKate Stone     if (error.Success()) {
186*b9c1b51eSKate Stone       // If our read was not aligned (for ah,bh,ch,dh), shift our returned value
187*b9c1b51eSKate Stone       // one byte to the right.
1883f57216cSOmair Javaid       if (is_subreg && (reg_info->byte_offset & 0x1))
1893f57216cSOmair Javaid         reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
1903f57216cSOmair Javaid 
191*b9c1b51eSKate Stone       // If our return byte size was greater than the return value reg size,
192*b9c1b51eSKate Stone       // then
1933f57216cSOmair Javaid       // use the type specified by reg_info rather than the uint64_t default
1943f57216cSOmair Javaid       if (reg_value.GetByteSize() > reg_info->byte_size)
1953f57216cSOmair Javaid         reg_value.SetType(reg_info);
1963f57216cSOmair Javaid     }
1973f57216cSOmair Javaid     return error;
1983f57216cSOmair Javaid   }
1993f57216cSOmair Javaid 
2003f57216cSOmair Javaid   // Get pointer to m_fpr variable and set the data from it.
201c40e7b17STamas Berghammer   uint32_t fpr_offset = CalculateFprOffset(reg_info);
202c40e7b17STamas Berghammer   assert(fpr_offset < sizeof m_fpr);
203c40e7b17STamas Berghammer   uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
204*b9c1b51eSKate Stone   switch (reg_info->byte_size) {
2053f57216cSOmair Javaid   case 2:
2063f57216cSOmair Javaid     reg_value.SetUInt16(*(uint16_t *)src);
2073f57216cSOmair Javaid     break;
2083f57216cSOmair Javaid   case 4:
2093f57216cSOmair Javaid     reg_value.SetUInt32(*(uint32_t *)src);
2103f57216cSOmair Javaid     break;
2113f57216cSOmair Javaid   case 8:
2123f57216cSOmair Javaid     reg_value.SetUInt64(*(uint64_t *)src);
2133f57216cSOmair Javaid     break;
214b4e95a50STamas Berghammer   case 16:
215b4e95a50STamas Berghammer     reg_value.SetBytes(src, 16, GetByteOrder());
216b4e95a50STamas Berghammer     break;
2173f57216cSOmair Javaid   default:
2183f57216cSOmair Javaid     assert(false && "Unhandled data size.");
219*b9c1b51eSKate Stone     error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32,
220*b9c1b51eSKate Stone                                    reg_info->byte_size);
2213f57216cSOmair Javaid     break;
2223f57216cSOmair Javaid   }
2233f57216cSOmair Javaid 
2243f57216cSOmair Javaid   return error;
2253f57216cSOmair Javaid }
2263f57216cSOmair Javaid 
227*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::WriteRegister(
228*b9c1b51eSKate Stone     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
2293f57216cSOmair Javaid   if (!reg_info)
2303f57216cSOmair Javaid     return Error("reg_info NULL");
2313f57216cSOmair Javaid 
2323f57216cSOmair Javaid   const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
2333f57216cSOmair Javaid   if (reg_index == LLDB_INVALID_REGNUM)
234*b9c1b51eSKate Stone     return Error("no lldb regnum for %s", reg_info && reg_info->name
235*b9c1b51eSKate Stone                                               ? reg_info->name
236*b9c1b51eSKate Stone                                               : "<unknown register>");
2373f57216cSOmair Javaid 
2383f57216cSOmair Javaid   if (IsGPR(reg_index))
2393f57216cSOmair Javaid     return WriteRegisterRaw(reg_index, reg_value);
2403f57216cSOmair Javaid 
241*b9c1b51eSKate Stone   if (IsFPR(reg_index)) {
2423f57216cSOmair Javaid     // Get pointer to m_fpr variable and set the data to it.
243c40e7b17STamas Berghammer     uint32_t fpr_offset = CalculateFprOffset(reg_info);
244c40e7b17STamas Berghammer     assert(fpr_offset < sizeof m_fpr);
245c40e7b17STamas Berghammer     uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
246*b9c1b51eSKate Stone     switch (reg_info->byte_size) {
2473f57216cSOmair Javaid     case 2:
2483f57216cSOmair Javaid       *(uint16_t *)dst = reg_value.GetAsUInt16();
2493f57216cSOmair Javaid       break;
2503f57216cSOmair Javaid     case 4:
2513f57216cSOmair Javaid       *(uint32_t *)dst = reg_value.GetAsUInt32();
2523f57216cSOmair Javaid       break;
2533f57216cSOmair Javaid     case 8:
2543f57216cSOmair Javaid       *(uint64_t *)dst = reg_value.GetAsUInt64();
2553f57216cSOmair Javaid       break;
2563f57216cSOmair Javaid     default:
2573f57216cSOmair Javaid       assert(false && "Unhandled data size.");
258*b9c1b51eSKate Stone       return Error("unhandled register data size %" PRIu32,
259*b9c1b51eSKate Stone                    reg_info->byte_size);
2603f57216cSOmair Javaid     }
2613f57216cSOmair Javaid 
262068f8a7eSTamas Berghammer     Error error = WriteFPR();
263068f8a7eSTamas Berghammer     if (error.Fail())
264068f8a7eSTamas Berghammer       return error;
2653f57216cSOmair Javaid 
2663f57216cSOmair Javaid     return Error();
2673f57216cSOmair Javaid   }
2683f57216cSOmair Javaid 
269*b9c1b51eSKate Stone   return Error("failed - register wasn't recognized to be a GPR or an FPR, "
270*b9c1b51eSKate Stone                "write strategy unknown");
2713f57216cSOmair Javaid }
2723f57216cSOmair Javaid 
273*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ReadAllRegisterValues(
274*b9c1b51eSKate Stone     lldb::DataBufferSP &data_sp) {
2753f57216cSOmair Javaid   Error error;
2763f57216cSOmair Javaid 
2773f57216cSOmair Javaid   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
2783f57216cSOmair Javaid   if (!data_sp)
279*b9c1b51eSKate Stone     return Error("failed to allocate DataBufferHeap instance of size %" PRIu64,
280*b9c1b51eSKate Stone                  (uint64_t)REG_CONTEXT_SIZE);
2813f57216cSOmair Javaid 
282068f8a7eSTamas Berghammer   error = ReadGPR();
283068f8a7eSTamas Berghammer   if (error.Fail())
2843f57216cSOmair Javaid     return error;
2853f57216cSOmair Javaid 
286068f8a7eSTamas Berghammer   error = ReadFPR();
287068f8a7eSTamas Berghammer   if (error.Fail())
2883f57216cSOmair Javaid     return error;
2893f57216cSOmair Javaid 
2903f57216cSOmair Javaid   uint8_t *dst = data_sp->GetBytes();
291*b9c1b51eSKate Stone   if (dst == nullptr) {
292*b9c1b51eSKate Stone     error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
293*b9c1b51eSKate Stone                                    " returned a null pointer",
294*b9c1b51eSKate Stone                                    (uint64_t)REG_CONTEXT_SIZE);
2953f57216cSOmair Javaid     return error;
2963f57216cSOmair Javaid   }
2973f57216cSOmair Javaid 
2983f57216cSOmair Javaid   ::memcpy(dst, &m_gpr_arm, GetGPRSize());
2993f57216cSOmair Javaid   dst += GetGPRSize();
3003f57216cSOmair Javaid   ::memcpy(dst, &m_fpr, sizeof(m_fpr));
3013f57216cSOmair Javaid 
3023f57216cSOmair Javaid   return error;
3033f57216cSOmair Javaid }
3043f57216cSOmair Javaid 
305*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::WriteAllRegisterValues(
306*b9c1b51eSKate Stone     const lldb::DataBufferSP &data_sp) {
3073f57216cSOmair Javaid   Error error;
3083f57216cSOmair Javaid 
309*b9c1b51eSKate Stone   if (!data_sp) {
310*b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
311*b9c1b51eSKate Stone         "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided",
312*b9c1b51eSKate Stone         __FUNCTION__);
3133f57216cSOmair Javaid     return error;
3143f57216cSOmair Javaid   }
3153f57216cSOmair Javaid 
316*b9c1b51eSKate Stone   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
317*b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
318*b9c1b51eSKate Stone         "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched "
319*b9c1b51eSKate Stone         "data size, expected %" PRIu64 ", actual %" PRIu64,
320*b9c1b51eSKate Stone         __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize());
3213f57216cSOmair Javaid     return error;
3223f57216cSOmair Javaid   }
3233f57216cSOmair Javaid 
3243f57216cSOmair Javaid   uint8_t *src = data_sp->GetBytes();
325*b9c1b51eSKate Stone   if (src == nullptr) {
326*b9c1b51eSKate Stone     error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s "
327*b9c1b51eSKate Stone                                    "DataBuffer::GetBytes() returned a null "
328*b9c1b51eSKate Stone                                    "pointer",
329*b9c1b51eSKate Stone                                    __FUNCTION__);
3303f57216cSOmair Javaid     return error;
3313f57216cSOmair Javaid   }
3323f57216cSOmair Javaid   ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize());
3333f57216cSOmair Javaid 
334068f8a7eSTamas Berghammer   error = WriteGPR();
335068f8a7eSTamas Berghammer   if (error.Fail())
3363f57216cSOmair Javaid     return error;
3373f57216cSOmair Javaid 
3383f57216cSOmair Javaid   src += GetRegisterInfoInterface().GetGPRSize();
3393f57216cSOmair Javaid   ::memcpy(&m_fpr, src, sizeof(m_fpr));
3403f57216cSOmair Javaid 
341068f8a7eSTamas Berghammer   error = WriteFPR();
3423f57216cSOmair Javaid   if (error.Fail())
3433f57216cSOmair Javaid     return error;
3443f57216cSOmair Javaid 
3453f57216cSOmair Javaid   return error;
3463f57216cSOmair Javaid }
3473f57216cSOmair Javaid 
348*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const {
3493f57216cSOmair Javaid   return reg <= m_reg_info.last_gpr; // GPR's come first.
3503f57216cSOmair Javaid }
3513f57216cSOmair Javaid 
352*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const {
3533f57216cSOmair Javaid   return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
3543f57216cSOmair Javaid }
3553f57216cSOmair Javaid 
3562441aecdSOmair Javaid uint32_t
357*b9c1b51eSKate Stone NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
358*b9c1b51eSKate Stone                                                       size_t size) {
3592441aecdSOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
3602441aecdSOmair Javaid 
3612441aecdSOmair Javaid   if (log)
3622441aecdSOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
3632441aecdSOmair Javaid 
3642441aecdSOmair Javaid   Error error;
3652441aecdSOmair Javaid 
3662441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
3672441aecdSOmair Javaid   error = ReadHardwareDebugInfo();
3682441aecdSOmair Javaid 
3692441aecdSOmair Javaid   if (error.Fail())
3702441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
3712441aecdSOmair Javaid 
3722441aecdSOmair Javaid   uint32_t control_value = 0, bp_index = 0;
3732441aecdSOmair Javaid 
3742441aecdSOmair Javaid   // Check if size has a valid hardware breakpoint length.
3752441aecdSOmair Javaid   // Thumb instructions are 2-bytes but we have no way here to determine
3762441aecdSOmair Javaid   // if target address is a thumb or arm instruction.
3772441aecdSOmair Javaid   // TODO: Add support for setting thumb mode hardware breakpoints
3782441aecdSOmair Javaid   if (size != 4 && size != 2)
3792441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
3802441aecdSOmair Javaid 
3812441aecdSOmair Javaid   // Setup control value
3822441aecdSOmair Javaid   // Make the byte_mask into a valid Byte Address Select mask
3832441aecdSOmair Javaid   control_value = 0xfu << 5;
3842441aecdSOmair Javaid 
3852441aecdSOmair Javaid   // Enable this breakpoint and make it stop in privileged or user mode;
3862441aecdSOmair Javaid   control_value |= 7;
3872441aecdSOmair Javaid 
3882441aecdSOmair Javaid   // Make sure bits 1:0 are clear in our address
3892441aecdSOmair Javaid   // This should be different once we support thumb here.
3902441aecdSOmair Javaid   addr &= ~((lldb::addr_t)3);
3912441aecdSOmair Javaid 
3922441aecdSOmair Javaid   // Iterate over stored hardware breakpoints
3932441aecdSOmair Javaid   // Find a free bp_index or update reference count if duplicate.
3942441aecdSOmair Javaid   bp_index = LLDB_INVALID_INDEX32;
3952441aecdSOmair Javaid 
396*b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
397*b9c1b51eSKate Stone     if ((m_hbr_regs[i].control & 1) == 0) {
3982441aecdSOmair Javaid       bp_index = i; // Mark last free slot
399*b9c1b51eSKate Stone     } else if (m_hbr_regs[i].address == addr &&
400*b9c1b51eSKate Stone                m_hbr_regs[i].control == control_value) {
4012441aecdSOmair Javaid       bp_index = i; // Mark duplicate index
4022441aecdSOmair Javaid       break;        // Stop searching here
4032441aecdSOmair Javaid     }
4042441aecdSOmair Javaid   }
4052441aecdSOmair Javaid 
4062441aecdSOmair Javaid   if (bp_index == LLDB_INVALID_INDEX32)
4072441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
4082441aecdSOmair Javaid 
4094aa984c1SOmair Javaid   // Add new or update existing breakpoint
410*b9c1b51eSKate Stone   if ((m_hbr_regs[bp_index].control & 1) == 0) {
4112441aecdSOmair Javaid     m_hbr_regs[bp_index].address = addr;
4122441aecdSOmair Javaid     m_hbr_regs[bp_index].control = control_value;
4132441aecdSOmair Javaid     m_hbr_regs[bp_index].refcount = 1;
4142441aecdSOmair Javaid 
4152441aecdSOmair Javaid     // PTRACE call to set corresponding hardware breakpoint register.
4162441aecdSOmair Javaid     error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
4172441aecdSOmair Javaid 
418*b9c1b51eSKate Stone     if (error.Fail()) {
419d5510d1eSOmair Javaid       m_hbr_regs[bp_index].address = 0;
420d5510d1eSOmair Javaid       m_hbr_regs[bp_index].control &= ~1;
421d5510d1eSOmair Javaid       m_hbr_regs[bp_index].refcount = 0;
422d5510d1eSOmair Javaid 
4232441aecdSOmair Javaid       return LLDB_INVALID_INDEX32;
4242441aecdSOmair Javaid     }
425*b9c1b51eSKate Stone   } else
4262441aecdSOmair Javaid     m_hbr_regs[bp_index].refcount++;
4272441aecdSOmair Javaid 
4282441aecdSOmair Javaid   return bp_index;
4292441aecdSOmair Javaid }
4302441aecdSOmair Javaid 
431*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
4322441aecdSOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
4332441aecdSOmair Javaid 
4342441aecdSOmair Javaid   if (log)
4352441aecdSOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
4362441aecdSOmair Javaid 
4372441aecdSOmair Javaid   Error error;
4382441aecdSOmair Javaid 
4392441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
4402441aecdSOmair Javaid   error = ReadHardwareDebugInfo();
4412441aecdSOmair Javaid 
4422441aecdSOmair Javaid   if (error.Fail())
4434aa984c1SOmair Javaid     return false;
4442441aecdSOmair Javaid 
4452441aecdSOmair Javaid   if (hw_idx >= m_max_hbp_supported)
4462441aecdSOmair Javaid     return false;
4472441aecdSOmair Javaid 
4482441aecdSOmair Javaid   // Update reference count if multiple references.
449*b9c1b51eSKate Stone   if (m_hbr_regs[hw_idx].refcount > 1) {
4502441aecdSOmair Javaid     m_hbr_regs[hw_idx].refcount--;
4512441aecdSOmair Javaid     return true;
452*b9c1b51eSKate Stone   } else if (m_hbr_regs[hw_idx].refcount == 1) {
453d5510d1eSOmair Javaid     // Create a backup we can revert to in case of failure.
454d5510d1eSOmair Javaid     lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
455d5510d1eSOmair Javaid     uint32_t tempControl = m_hbr_regs[hw_idx].control;
456d5510d1eSOmair Javaid     uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount;
457d5510d1eSOmair Javaid 
4582441aecdSOmair Javaid     m_hbr_regs[hw_idx].control &= ~1;
4592441aecdSOmair Javaid     m_hbr_regs[hw_idx].address = 0;
4602441aecdSOmair Javaid     m_hbr_regs[hw_idx].refcount = 0;
4612441aecdSOmair Javaid 
4622441aecdSOmair Javaid     // PTRACE call to clear corresponding hardware breakpoint register.
4632441aecdSOmair Javaid     WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
4642441aecdSOmair Javaid 
465*b9c1b51eSKate Stone     if (error.Fail()) {
466d5510d1eSOmair Javaid       m_hbr_regs[hw_idx].control = tempControl;
467d5510d1eSOmair Javaid       m_hbr_regs[hw_idx].address = tempAddr;
468d5510d1eSOmair Javaid       m_hbr_regs[hw_idx].refcount = tempRefCount;
469d5510d1eSOmair Javaid 
4704aa984c1SOmair Javaid       return false;
471d5510d1eSOmair Javaid     }
4722441aecdSOmair Javaid 
4732441aecdSOmair Javaid     return true;
4742441aecdSOmair Javaid   }
4752441aecdSOmair Javaid 
4762441aecdSOmair Javaid   return false;
4772441aecdSOmair Javaid }
4782441aecdSOmair Javaid 
479*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
4802441aecdSOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
4812441aecdSOmair Javaid 
4822441aecdSOmair Javaid   if (log)
4832441aecdSOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
4842441aecdSOmair Javaid 
4852441aecdSOmair Javaid   Error error;
4862441aecdSOmair Javaid 
4872441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
4882441aecdSOmair Javaid   error = ReadHardwareDebugInfo();
4892441aecdSOmair Javaid 
4902441aecdSOmair Javaid   if (error.Fail())
49162661473SOmair Javaid     return 0;
4922441aecdSOmair Javaid 
4932441aecdSOmair Javaid   return m_max_hwp_supported;
4942441aecdSOmair Javaid }
4952441aecdSOmair Javaid 
496*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
497*b9c1b51eSKate Stone     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
4982441aecdSOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
4992441aecdSOmair Javaid 
5002441aecdSOmair Javaid   if (log)
5012441aecdSOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
5022441aecdSOmair Javaid 
5032441aecdSOmair Javaid   Error error;
5042441aecdSOmair Javaid 
5052441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
5062441aecdSOmair Javaid   error = ReadHardwareDebugInfo();
5072441aecdSOmair Javaid 
5082441aecdSOmair Javaid   if (error.Fail())
5092441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5102441aecdSOmair Javaid 
5112441aecdSOmair Javaid   uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
512c6dc90efSOmair Javaid   lldb::addr_t real_addr = addr;
5132441aecdSOmair Javaid 
5142441aecdSOmair Javaid   // Check if we are setting watchpoint other than read/write/access
5152441aecdSOmair Javaid   // Also update watchpoint flag to match Arm write-read bit configuration.
516*b9c1b51eSKate Stone   switch (watch_flags) {
5172441aecdSOmair Javaid   case 1:
5182441aecdSOmair Javaid     watch_flags = 2;
5192441aecdSOmair Javaid     break;
5202441aecdSOmair Javaid   case 2:
5212441aecdSOmair Javaid     watch_flags = 1;
5222441aecdSOmair Javaid     break;
5232441aecdSOmair Javaid   case 3:
5242441aecdSOmair Javaid     break;
5252441aecdSOmair Javaid   default:
5262441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5272441aecdSOmair Javaid   }
5282441aecdSOmair Javaid 
5292441aecdSOmair Javaid   // Can't watch zero bytes
5302441aecdSOmair Javaid   // Can't watch more than 4 bytes per WVR/WCR pair
5312441aecdSOmair Javaid 
5322441aecdSOmair Javaid   if (size == 0 || size > 4)
5332441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5342441aecdSOmair Javaid 
535c6dc90efSOmair Javaid   // Check 4-byte alignment for hardware watchpoint target address.
536c6dc90efSOmair Javaid   // Below is a hack to recalculate address and size in order to
537c6dc90efSOmair Javaid   // make sure we can watch non 4-byte alligned addresses as well.
538*b9c1b51eSKate Stone   if (addr & 0x03) {
539c6dc90efSOmair Javaid     uint8_t watch_mask = (addr & 0x03) + size;
540c6dc90efSOmair Javaid 
541c6dc90efSOmair Javaid     if (watch_mask > 0x04)
542c6dc90efSOmair Javaid       return LLDB_INVALID_INDEX32;
543c6dc90efSOmair Javaid     else if (watch_mask <= 0x02)
544c6dc90efSOmair Javaid       size = 2;
545c6dc90efSOmair Javaid     else if (watch_mask <= 0x04)
546c6dc90efSOmair Javaid       size = 4;
547c6dc90efSOmair Javaid 
548c6dc90efSOmair Javaid     addr = addr & (~0x03);
549c6dc90efSOmair Javaid   }
550c6dc90efSOmair Javaid 
5512441aecdSOmair Javaid   // We can only watch up to four bytes that follow a 4 byte aligned address
5522441aecdSOmair Javaid   // per watchpoint register pair, so make sure we can properly encode this.
5532441aecdSOmair Javaid   addr_word_offset = addr % 4;
5542441aecdSOmair Javaid   byte_mask = ((1u << size) - 1u) << addr_word_offset;
5552441aecdSOmair Javaid 
5562441aecdSOmair Javaid   // Check if we need multiple watchpoint register
5572441aecdSOmair Javaid   if (byte_mask > 0xfu)
5582441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5592441aecdSOmair Javaid 
5602441aecdSOmair Javaid   // Setup control value
5612441aecdSOmair Javaid   // Make the byte_mask into a valid Byte Address Select mask
5622441aecdSOmair Javaid   control_value = byte_mask << 5;
5632441aecdSOmair Javaid 
5642441aecdSOmair Javaid   // Turn on appropriate watchpoint flags read or write
5652441aecdSOmair Javaid   control_value |= (watch_flags << 3);
5662441aecdSOmair Javaid 
5672441aecdSOmair Javaid   // Enable this watchpoint and make it stop in privileged or user mode;
5682441aecdSOmair Javaid   control_value |= 7;
5692441aecdSOmair Javaid 
5702441aecdSOmair Javaid   // Make sure bits 1:0 are clear in our address
5712441aecdSOmair Javaid   addr &= ~((lldb::addr_t)3);
5722441aecdSOmair Javaid 
5732441aecdSOmair Javaid   // Iterate over stored watchpoints
5742441aecdSOmair Javaid   // Find a free wp_index or update reference count if duplicate.
5752441aecdSOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
576*b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
577*b9c1b51eSKate Stone     if ((m_hwp_regs[i].control & 1) == 0) {
5782441aecdSOmair Javaid       wp_index = i; // Mark last free slot
579*b9c1b51eSKate Stone     } else if (m_hwp_regs[i].address == addr &&
580*b9c1b51eSKate Stone                m_hwp_regs[i].control == control_value) {
5812441aecdSOmair Javaid       wp_index = i; // Mark duplicate index
5822441aecdSOmair Javaid       break;        // Stop searching here
5832441aecdSOmair Javaid     }
5842441aecdSOmair Javaid   }
5852441aecdSOmair Javaid 
5862441aecdSOmair Javaid   if (wp_index == LLDB_INVALID_INDEX32)
5872441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5882441aecdSOmair Javaid 
5892441aecdSOmair Javaid   // Add new or update existing watchpoint
590*b9c1b51eSKate Stone   if ((m_hwp_regs[wp_index].control & 1) == 0) {
5912441aecdSOmair Javaid     // Update watchpoint in local cache
592c6dc90efSOmair Javaid     m_hwp_regs[wp_index].real_addr = real_addr;
5932441aecdSOmair Javaid     m_hwp_regs[wp_index].address = addr;
5942441aecdSOmair Javaid     m_hwp_regs[wp_index].control = control_value;
5952441aecdSOmair Javaid     m_hwp_regs[wp_index].refcount = 1;
5962441aecdSOmair Javaid 
5972441aecdSOmair Javaid     // PTRACE call to set corresponding watchpoint register.
5982441aecdSOmair Javaid     error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
5992441aecdSOmair Javaid 
600*b9c1b51eSKate Stone     if (error.Fail()) {
601d5510d1eSOmair Javaid       m_hwp_regs[wp_index].address = 0;
602d5510d1eSOmair Javaid       m_hwp_regs[wp_index].control &= ~1;
603d5510d1eSOmair Javaid       m_hwp_regs[wp_index].refcount = 0;
604d5510d1eSOmair Javaid 
6052441aecdSOmair Javaid       return LLDB_INVALID_INDEX32;
6062441aecdSOmair Javaid     }
607*b9c1b51eSKate Stone   } else
6082441aecdSOmair Javaid     m_hwp_regs[wp_index].refcount++;
6092441aecdSOmair Javaid 
6102441aecdSOmair Javaid   return wp_index;
6112441aecdSOmair Javaid }
6122441aecdSOmair Javaid 
613*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
614*b9c1b51eSKate Stone     uint32_t wp_index) {
6152441aecdSOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
6162441aecdSOmair Javaid 
6172441aecdSOmair Javaid   if (log)
6182441aecdSOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
6192441aecdSOmair Javaid 
6202441aecdSOmair Javaid   Error error;
6212441aecdSOmair Javaid 
6222441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
6232441aecdSOmair Javaid   error = ReadHardwareDebugInfo();
6242441aecdSOmair Javaid 
6252441aecdSOmair Javaid   if (error.Fail())
6264aa984c1SOmair Javaid     return false;
6272441aecdSOmair Javaid 
6282441aecdSOmair Javaid   if (wp_index >= m_max_hwp_supported)
6292441aecdSOmair Javaid     return false;
6302441aecdSOmair Javaid 
6312441aecdSOmair Javaid   // Update reference count if multiple references.
632*b9c1b51eSKate Stone   if (m_hwp_regs[wp_index].refcount > 1) {
6332441aecdSOmair Javaid     m_hwp_regs[wp_index].refcount--;
6342441aecdSOmair Javaid     return true;
635*b9c1b51eSKate Stone   } else if (m_hwp_regs[wp_index].refcount == 1) {
636d5510d1eSOmair Javaid     // Create a backup we can revert to in case of failure.
637d5510d1eSOmair Javaid     lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
638d5510d1eSOmair Javaid     uint32_t tempControl = m_hwp_regs[wp_index].control;
639d5510d1eSOmair Javaid     uint32_t tempRefCount = m_hwp_regs[wp_index].refcount;
640d5510d1eSOmair Javaid 
6412441aecdSOmair Javaid     // Update watchpoint in local cache
6422441aecdSOmair Javaid     m_hwp_regs[wp_index].control &= ~1;
6432441aecdSOmair Javaid     m_hwp_regs[wp_index].address = 0;
6442441aecdSOmair Javaid     m_hwp_regs[wp_index].refcount = 0;
6452441aecdSOmair Javaid 
6462441aecdSOmair Javaid     // Ptrace call to update hardware debug registers
6472441aecdSOmair Javaid     error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
6482441aecdSOmair Javaid 
649*b9c1b51eSKate Stone     if (error.Fail()) {
650d5510d1eSOmair Javaid       m_hwp_regs[wp_index].control = tempControl;
651d5510d1eSOmair Javaid       m_hwp_regs[wp_index].address = tempAddr;
652d5510d1eSOmair Javaid       m_hwp_regs[wp_index].refcount = tempRefCount;
653d5510d1eSOmair Javaid 
6542441aecdSOmair Javaid       return false;
655d5510d1eSOmair Javaid     }
6562441aecdSOmair Javaid 
6572441aecdSOmair Javaid     return true;
6582441aecdSOmair Javaid   }
6592441aecdSOmair Javaid 
6602441aecdSOmair Javaid   return false;
6612441aecdSOmair Javaid }
6622441aecdSOmair Javaid 
663*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
6642441aecdSOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
6652441aecdSOmair Javaid 
6662441aecdSOmair Javaid   if (log)
6672441aecdSOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
6682441aecdSOmair Javaid 
6692441aecdSOmair Javaid   Error error;
6702441aecdSOmair Javaid 
6712441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
6722441aecdSOmair Javaid   error = ReadHardwareDebugInfo();
6732441aecdSOmair Javaid 
6742441aecdSOmair Javaid   if (error.Fail())
6752441aecdSOmair Javaid     return error;
6762441aecdSOmair Javaid 
677d5510d1eSOmair Javaid   lldb::addr_t tempAddr = 0;
678d5510d1eSOmair Javaid   uint32_t tempControl = 0, tempRefCount = 0;
679d5510d1eSOmair Javaid 
680*b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
681*b9c1b51eSKate Stone     if (m_hwp_regs[i].control & 0x01) {
682d5510d1eSOmair Javaid       // Create a backup we can revert to in case of failure.
683d5510d1eSOmair Javaid       tempAddr = m_hwp_regs[i].address;
684d5510d1eSOmair Javaid       tempControl = m_hwp_regs[i].control;
685d5510d1eSOmair Javaid       tempRefCount = m_hwp_regs[i].refcount;
686d5510d1eSOmair Javaid 
6872441aecdSOmair Javaid       // Clear watchpoints in local cache
6882441aecdSOmair Javaid       m_hwp_regs[i].control &= ~1;
6892441aecdSOmair Javaid       m_hwp_regs[i].address = 0;
6902441aecdSOmair Javaid       m_hwp_regs[i].refcount = 0;
6912441aecdSOmair Javaid 
6922441aecdSOmair Javaid       // Ptrace call to update hardware debug registers
6932441aecdSOmair Javaid       error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
6942441aecdSOmair Javaid 
695*b9c1b51eSKate Stone       if (error.Fail()) {
696d5510d1eSOmair Javaid         m_hwp_regs[i].control = tempControl;
697d5510d1eSOmair Javaid         m_hwp_regs[i].address = tempAddr;
698d5510d1eSOmair Javaid         m_hwp_regs[i].refcount = tempRefCount;
699d5510d1eSOmair Javaid 
7002441aecdSOmair Javaid         return error;
7012441aecdSOmair Javaid       }
7022441aecdSOmair Javaid     }
703d5510d1eSOmair Javaid   }
7042441aecdSOmair Javaid 
7052441aecdSOmair Javaid   return Error();
7062441aecdSOmair Javaid }
7072441aecdSOmair Javaid 
708*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) {
7092441aecdSOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
7102441aecdSOmair Javaid 
7112441aecdSOmair Javaid   if (log)
7122441aecdSOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7132441aecdSOmair Javaid 
714*b9c1b51eSKate Stone   switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
7152441aecdSOmair Javaid   case 0x01:
7162441aecdSOmair Javaid     return 1;
7172441aecdSOmair Javaid   case 0x03:
7182441aecdSOmair Javaid     return 2;
7192441aecdSOmair Javaid   case 0x07:
7202441aecdSOmair Javaid     return 3;
7212441aecdSOmair Javaid   case 0x0f:
7222441aecdSOmair Javaid     return 4;
7232441aecdSOmair Javaid   default:
7242441aecdSOmair Javaid     return 0;
7252441aecdSOmair Javaid   }
7262441aecdSOmair Javaid }
727*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) {
7282441aecdSOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
7292441aecdSOmair Javaid 
7302441aecdSOmair Javaid   if (log)
7312441aecdSOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7322441aecdSOmair Javaid 
7332441aecdSOmair Javaid   if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
7342441aecdSOmair Javaid     return true;
7352441aecdSOmair Javaid   else
7362441aecdSOmair Javaid     return false;
7372441aecdSOmair Javaid }
7382441aecdSOmair Javaid 
739*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::GetWatchpointHitIndex(
740*b9c1b51eSKate Stone     uint32_t &wp_index, lldb::addr_t trap_addr) {
7412441aecdSOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
7422441aecdSOmair Javaid 
7432441aecdSOmair Javaid   if (log)
7442441aecdSOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7452441aecdSOmair Javaid 
7462441aecdSOmair Javaid   uint32_t watch_size;
7472441aecdSOmair Javaid   lldb::addr_t watch_addr;
7482441aecdSOmair Javaid 
749*b9c1b51eSKate Stone   for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
7502441aecdSOmair Javaid     watch_size = GetWatchpointSize(wp_index);
7512441aecdSOmair Javaid     watch_addr = m_hwp_regs[wp_index].address;
7522441aecdSOmair Javaid 
753*b9c1b51eSKate Stone     if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) &&
754*b9c1b51eSKate Stone         trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) {
755c6dc90efSOmair Javaid       m_hwp_regs[wp_index].hit_addr = trap_addr;
7562441aecdSOmair Javaid       return Error();
7572441aecdSOmair Javaid     }
7582441aecdSOmair Javaid   }
7592441aecdSOmair Javaid 
7602441aecdSOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
7612441aecdSOmair Javaid   return Error();
7622441aecdSOmair Javaid }
7632441aecdSOmair Javaid 
7642441aecdSOmair Javaid lldb::addr_t
765*b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) {
7662441aecdSOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
7672441aecdSOmair Javaid 
7682441aecdSOmair Javaid   if (log)
7692441aecdSOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
7702441aecdSOmair Javaid 
7712441aecdSOmair Javaid   if (wp_index >= m_max_hwp_supported)
7722441aecdSOmair Javaid     return LLDB_INVALID_ADDRESS;
7732441aecdSOmair Javaid 
7742441aecdSOmair Javaid   if (WatchpointIsEnabled(wp_index))
775c6dc90efSOmair Javaid     return m_hwp_regs[wp_index].real_addr;
776c6dc90efSOmair Javaid   else
777c6dc90efSOmair Javaid     return LLDB_INVALID_ADDRESS;
778c6dc90efSOmair Javaid }
779c6dc90efSOmair Javaid 
780c6dc90efSOmair Javaid lldb::addr_t
781*b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) {
782c6dc90efSOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
783c6dc90efSOmair Javaid 
784c6dc90efSOmair Javaid   if (log)
785c6dc90efSOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
786c6dc90efSOmair Javaid 
787c6dc90efSOmair Javaid   if (wp_index >= m_max_hwp_supported)
788c6dc90efSOmair Javaid     return LLDB_INVALID_ADDRESS;
789c6dc90efSOmair Javaid 
790c6dc90efSOmair Javaid   if (WatchpointIsEnabled(wp_index))
791c6dc90efSOmair Javaid     return m_hwp_regs[wp_index].hit_addr;
7922441aecdSOmair Javaid   else
7932441aecdSOmair Javaid     return LLDB_INVALID_ADDRESS;
7942441aecdSOmair Javaid }
7952441aecdSOmair Javaid 
796*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
7972441aecdSOmair Javaid   Error error;
7982441aecdSOmair Javaid 
799*b9c1b51eSKate Stone   if (!m_refresh_hwdebug_info) {
8002441aecdSOmair Javaid     return Error();
8012441aecdSOmair Javaid   }
8022441aecdSOmair Javaid 
8032441aecdSOmair Javaid   unsigned int cap_val;
8042441aecdSOmair Javaid 
805*b9c1b51eSKate Stone   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(),
806*b9c1b51eSKate Stone                                             nullptr, &cap_val,
807*b9c1b51eSKate Stone                                             sizeof(unsigned int));
8082441aecdSOmair Javaid 
8092441aecdSOmair Javaid   if (error.Fail())
8102441aecdSOmair Javaid     return error;
8112441aecdSOmair Javaid 
8122441aecdSOmair Javaid   m_max_hwp_supported = (cap_val >> 8) & 0xff;
8132441aecdSOmair Javaid   m_max_hbp_supported = cap_val & 0xff;
8142441aecdSOmair Javaid   m_refresh_hwdebug_info = false;
8152441aecdSOmair Javaid 
8162441aecdSOmair Javaid   return error;
8172441aecdSOmair Javaid }
8182441aecdSOmair Javaid 
819*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType,
820*b9c1b51eSKate Stone                                                              int hwb_index) {
8212441aecdSOmair Javaid   Error error;
8222441aecdSOmair Javaid 
8232441aecdSOmair Javaid   lldb::addr_t *addr_buf;
8242441aecdSOmair Javaid   uint32_t *ctrl_buf;
8252441aecdSOmair Javaid 
826*b9c1b51eSKate Stone   if (hwbType == eDREGTypeWATCH) {
8272441aecdSOmair Javaid     addr_buf = &m_hwp_regs[hwb_index].address;
8282441aecdSOmair Javaid     ctrl_buf = &m_hwp_regs[hwb_index].control;
8292441aecdSOmair Javaid 
830*b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
831*b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
832*b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf,
833*b9c1b51eSKate Stone         sizeof(unsigned int));
8342441aecdSOmair Javaid 
8352441aecdSOmair Javaid     if (error.Fail())
8362441aecdSOmair Javaid       return error;
8372441aecdSOmair Javaid 
838*b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
839*b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
840*b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
841*b9c1b51eSKate Stone         sizeof(unsigned int));
842*b9c1b51eSKate Stone   } else {
8432441aecdSOmair Javaid     addr_buf = &m_hwp_regs[hwb_index].address;
8442441aecdSOmair Javaid     ctrl_buf = &m_hwp_regs[hwb_index].control;
8452441aecdSOmair Javaid 
846*b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
847*b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
848*b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf,
849*b9c1b51eSKate Stone         sizeof(unsigned int));
8502441aecdSOmair Javaid 
8512441aecdSOmair Javaid     if (error.Fail())
8522441aecdSOmair Javaid       return error;
8532441aecdSOmair Javaid 
854*b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
855*b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
856*b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
857*b9c1b51eSKate Stone         sizeof(unsigned int));
8582441aecdSOmair Javaid   }
8592441aecdSOmair Javaid 
8602441aecdSOmair Javaid   return error;
8612441aecdSOmair Javaid }
862c40e7b17STamas Berghammer 
863*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
864*b9c1b51eSKate Stone     const RegisterInfo *reg_info) const {
865*b9c1b51eSKate Stone   return reg_info->byte_offset -
866*b9c1b51eSKate Stone          GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
867c40e7b17STamas Berghammer }
868c40e7b17STamas Berghammer 
869*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoReadRegisterValue(
870*b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, uint32_t size,
871*b9c1b51eSKate Stone     RegisterValue &value) {
872*b9c1b51eSKate Stone   // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android
873*b9c1b51eSKate Stone   // devices (always return
874*b9c1b51eSKate Stone   // "Bad address"). To avoid using PTRACE_PEEKUSER we read out the full GPR
875*b9c1b51eSKate Stone   // register set instead.
876*b9c1b51eSKate Stone   // This approach is about 4 times slower but the performance overhead is
877*b9c1b51eSKate Stone   // negligible in
878e85e6021STamas Berghammer   // comparision to processing time in lldb-server.
879e85e6021STamas Berghammer   assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
880e85e6021STamas Berghammer   if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
881e85e6021STamas Berghammer     return Error("Register isn't fit into the size of the GPR area");
882e85e6021STamas Berghammer 
883e85e6021STamas Berghammer   Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm));
884e85e6021STamas Berghammer   if (error.Fail())
885e85e6021STamas Berghammer     return error;
886e85e6021STamas Berghammer 
887e85e6021STamas Berghammer   value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]);
888e85e6021STamas Berghammer   return Error();
889e85e6021STamas Berghammer }
890e85e6021STamas Berghammer 
891*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoWriteRegisterValue(
892*b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, const RegisterValue &value) {
893*b9c1b51eSKate Stone   // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android
894*b9c1b51eSKate Stone   // devices (always return
895*b9c1b51eSKate Stone   // "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR
896*b9c1b51eSKate Stone   // register set, modify
897*b9c1b51eSKate Stone   // the requested register and write it back. This approach is about 4 times
898*b9c1b51eSKate Stone   // slower but the
899*b9c1b51eSKate Stone   // performance overhead is negligible in comparision to processing time in
900*b9c1b51eSKate Stone   // lldb-server.
901ce26b7a6STamas Berghammer   assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
902ce26b7a6STamas Berghammer   if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
903ce26b7a6STamas Berghammer     return Error("Register isn't fit into the size of the GPR area");
904ce26b7a6STamas Berghammer 
905ce26b7a6STamas Berghammer   Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm));
906ce26b7a6STamas Berghammer   if (error.Fail())
907ce26b7a6STamas Berghammer     return error;
908ce26b7a6STamas Berghammer 
909a7d7f7cfSOmair Javaid   uint32_t reg_value = value.GetAsUInt32();
910a7d7f7cfSOmair Javaid   // As precaution for an undefined behavior encountered while setting PC we
911a7d7f7cfSOmair Javaid   // will clear thumb bit of new PC if we are already in thumb mode; that is
912a7d7f7cfSOmair Javaid   // CPSR thumb mode bit is set.
913*b9c1b51eSKate Stone   if (offset / sizeof(uint32_t) == gpr_pc_arm) {
914a7d7f7cfSOmair Javaid     // Check if we are already in thumb mode and
915a7d7f7cfSOmair Javaid     // thumb bit of current PC is read out to be zero and
916a7d7f7cfSOmair Javaid     // thumb bit of next PC is read out to be one.
917*b9c1b51eSKate Stone     if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) &&
918*b9c1b51eSKate Stone         (value.GetAsUInt32() & 0x01)) {
919a7d7f7cfSOmair Javaid       reg_value &= (~1ull);
920a7d7f7cfSOmair Javaid     }
921a7d7f7cfSOmair Javaid   }
922a7d7f7cfSOmair Javaid 
923a7d7f7cfSOmair Javaid   m_gpr_arm[offset / sizeof(uint32_t)] = reg_value;
924ce26b7a6STamas Berghammer   return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm));
925ce26b7a6STamas Berghammer }
926ce26b7a6STamas Berghammer 
927*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoReadGPR(void *buf, size_t buf_size) {
928e85e6021STamas Berghammer #ifdef __arm__
929e85e6021STamas Berghammer   return NativeRegisterContextLinux::DoReadGPR(buf, buf_size);
930e85e6021STamas Berghammer #else  // __aarch64__
931e85e6021STamas Berghammer   struct iovec ioVec;
932e85e6021STamas Berghammer   ioVec.iov_base = buf;
933e85e6021STamas Berghammer   ioVec.iov_len = buf_size;
934e85e6021STamas Berghammer 
935e85e6021STamas Berghammer   return ReadRegisterSet(&ioVec, buf_size, NT_PRSTATUS);
936e85e6021STamas Berghammer #endif // __arm__
937e85e6021STamas Berghammer }
938e85e6021STamas Berghammer 
939*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoWriteGPR(void *buf, size_t buf_size) {
940e85e6021STamas Berghammer #ifdef __arm__
941e85e6021STamas Berghammer   return NativeRegisterContextLinux::DoWriteGPR(buf, buf_size);
942e85e6021STamas Berghammer #else  // __aarch64__
943e85e6021STamas Berghammer   struct iovec ioVec;
944e85e6021STamas Berghammer   ioVec.iov_base = buf;
945e85e6021STamas Berghammer   ioVec.iov_len = buf_size;
946e85e6021STamas Berghammer 
947e85e6021STamas Berghammer   return WriteRegisterSet(&ioVec, buf_size, NT_PRSTATUS);
948e85e6021STamas Berghammer #endif // __arm__
949e85e6021STamas Berghammer }
950e85e6021STamas Berghammer 
951*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size) {
952e85e6021STamas Berghammer #ifdef __arm__
953*b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(),
954*b9c1b51eSKate Stone                                            nullptr, buf, buf_size);
955e85e6021STamas Berghammer #else  // __aarch64__
956e85e6021STamas Berghammer   struct iovec ioVec;
957e85e6021STamas Berghammer   ioVec.iov_base = buf;
958e85e6021STamas Berghammer   ioVec.iov_len = buf_size;
959e85e6021STamas Berghammer 
960e85e6021STamas Berghammer   return ReadRegisterSet(&ioVec, buf_size, NT_ARM_VFP);
961e85e6021STamas Berghammer #endif // __arm__
962ce26b7a6STamas Berghammer }
963ce26b7a6STamas Berghammer 
964*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size) {
965e85e6021STamas Berghammer #ifdef __arm__
966*b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(),
967*b9c1b51eSKate Stone                                            nullptr, buf, buf_size);
968e85e6021STamas Berghammer #else  // __aarch64__
969e85e6021STamas Berghammer   struct iovec ioVec;
970e85e6021STamas Berghammer   ioVec.iov_base = buf;
971e85e6021STamas Berghammer   ioVec.iov_len = buf_size;
972e85e6021STamas Berghammer 
973e85e6021STamas Berghammer   return WriteRegisterSet(&ioVec, buf_size, NT_ARM_VFP);
974e85e6021STamas Berghammer #endif // __arm__
975ce26b7a6STamas Berghammer }
976ce26b7a6STamas Berghammer 
977e85e6021STamas Berghammer #endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
978