11e209fccSTamas Berghammer //===-- NativeRegisterContextLinux_arm64.cpp --------------------*- C++ -*-===//
21e209fccSTamas Berghammer //
31e209fccSTamas Berghammer //                     The LLVM Compiler Infrastructure
41e209fccSTamas Berghammer //
51e209fccSTamas Berghammer // This file is distributed under the University of Illinois Open Source
61e209fccSTamas Berghammer // License. See LICENSE.TXT for details.
71e209fccSTamas Berghammer //
81e209fccSTamas Berghammer //===----------------------------------------------------------------------===//
91e209fccSTamas Berghammer 
10068f8a7eSTamas Berghammer #if defined(__arm64__) || defined(__aarch64__)
11068f8a7eSTamas Berghammer 
12e85e6021STamas Berghammer #include "NativeRegisterContextLinux_arm.h"
131e209fccSTamas Berghammer #include "NativeRegisterContextLinux_arm64.h"
141e209fccSTamas Berghammer 
15068f8a7eSTamas Berghammer // C Includes
16068f8a7eSTamas Berghammer // C++ Includes
17068f8a7eSTamas Berghammer 
18068f8a7eSTamas Berghammer // Other libraries and framework includes
191e209fccSTamas Berghammer #include "lldb/Core/DataBufferHeap.h"
201e209fccSTamas Berghammer #include "lldb/Core/Error.h"
21068f8a7eSTamas Berghammer #include "lldb/Core/Log.h"
221e209fccSTamas Berghammer #include "lldb/Core/RegisterValue.h"
231e209fccSTamas Berghammer #include "lldb/Host/common/NativeProcessProtocol.h"
241e209fccSTamas Berghammer 
25068f8a7eSTamas Berghammer #include "Plugins/Process/Linux/NativeProcessLinux.h"
26068f8a7eSTamas Berghammer #include "Plugins/Process/Linux/Procfs.h"
27e85e6021STamas Berghammer #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
28068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
29068f8a7eSTamas Berghammer 
30*b9c1b51eSKate Stone // System includes - They have to be included after framework includes because
31*b9c1b51eSKate Stone // they define some
32068f8a7eSTamas Berghammer // macros which collide with variable names in other modules
33068f8a7eSTamas Berghammer #include <sys/socket.h>
34068f8a7eSTamas Berghammer // NT_PRSTATUS and NT_FPREGSET definition
35068f8a7eSTamas Berghammer #include <elf.h>
36dd4799c2SSaleem Abdulrasool // user_hwdebug_state definition
37dd4799c2SSaleem Abdulrasool #include <asm/ptrace.h>
38068f8a7eSTamas Berghammer 
39068f8a7eSTamas Berghammer #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
401e209fccSTamas Berghammer 
411e209fccSTamas Berghammer using namespace lldb;
421e209fccSTamas Berghammer using namespace lldb_private;
43db264a6dSTamas Berghammer using namespace lldb_private::process_linux;
441e209fccSTamas Berghammer 
451e209fccSTamas Berghammer // ARM64 general purpose registers.
46*b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_arm64[] = {
47*b9c1b51eSKate Stone     gpr_x0_arm64,       gpr_x1_arm64,   gpr_x2_arm64,  gpr_x3_arm64,
48*b9c1b51eSKate Stone     gpr_x4_arm64,       gpr_x5_arm64,   gpr_x6_arm64,  gpr_x7_arm64,
49*b9c1b51eSKate Stone     gpr_x8_arm64,       gpr_x9_arm64,   gpr_x10_arm64, gpr_x11_arm64,
50*b9c1b51eSKate Stone     gpr_x12_arm64,      gpr_x13_arm64,  gpr_x14_arm64, gpr_x15_arm64,
51*b9c1b51eSKate Stone     gpr_x16_arm64,      gpr_x17_arm64,  gpr_x18_arm64, gpr_x19_arm64,
52*b9c1b51eSKate Stone     gpr_x20_arm64,      gpr_x21_arm64,  gpr_x22_arm64, gpr_x23_arm64,
53*b9c1b51eSKate Stone     gpr_x24_arm64,      gpr_x25_arm64,  gpr_x26_arm64, gpr_x27_arm64,
54*b9c1b51eSKate Stone     gpr_x28_arm64,      gpr_fp_arm64,   gpr_lr_arm64,  gpr_sp_arm64,
55*b9c1b51eSKate Stone     gpr_pc_arm64,       gpr_cpsr_arm64,
561e209fccSTamas Berghammer     LLDB_INVALID_REGNUM // register sets need to end with this flag
571e209fccSTamas Berghammer };
58*b9c1b51eSKate Stone static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) -
59*b9c1b51eSKate Stone                1) == k_num_gpr_registers_arm64,
601e209fccSTamas Berghammer               "g_gpr_regnums_arm64 has wrong number of register infos");
611e209fccSTamas Berghammer 
621e209fccSTamas Berghammer // ARM64 floating point registers.
63*b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_arm64[] = {
64*b9c1b51eSKate Stone     fpu_v0_arm64,       fpu_v1_arm64,   fpu_v2_arm64,  fpu_v3_arm64,
65*b9c1b51eSKate Stone     fpu_v4_arm64,       fpu_v5_arm64,   fpu_v6_arm64,  fpu_v7_arm64,
66*b9c1b51eSKate Stone     fpu_v8_arm64,       fpu_v9_arm64,   fpu_v10_arm64, fpu_v11_arm64,
67*b9c1b51eSKate Stone     fpu_v12_arm64,      fpu_v13_arm64,  fpu_v14_arm64, fpu_v15_arm64,
68*b9c1b51eSKate Stone     fpu_v16_arm64,      fpu_v17_arm64,  fpu_v18_arm64, fpu_v19_arm64,
69*b9c1b51eSKate Stone     fpu_v20_arm64,      fpu_v21_arm64,  fpu_v22_arm64, fpu_v23_arm64,
70*b9c1b51eSKate Stone     fpu_v24_arm64,      fpu_v25_arm64,  fpu_v26_arm64, fpu_v27_arm64,
71*b9c1b51eSKate Stone     fpu_v28_arm64,      fpu_v29_arm64,  fpu_v30_arm64, fpu_v31_arm64,
72*b9c1b51eSKate Stone     fpu_fpsr_arm64,     fpu_fpcr_arm64,
731e209fccSTamas Berghammer     LLDB_INVALID_REGNUM // register sets need to end with this flag
741e209fccSTamas Berghammer };
75*b9c1b51eSKate Stone static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) -
76*b9c1b51eSKate Stone                1) == k_num_fpr_registers_arm64,
771e209fccSTamas Berghammer               "g_fpu_regnums_arm64 has wrong number of register infos");
781e209fccSTamas Berghammer 
791e209fccSTamas Berghammer namespace {
801e209fccSTamas Berghammer // Number of register sets provided by this context.
81*b9c1b51eSKate Stone enum { k_num_register_sets = 2 };
821e209fccSTamas Berghammer }
831e209fccSTamas Berghammer 
841e209fccSTamas Berghammer // Register sets for ARM64.
85*b9c1b51eSKate Stone static const RegisterSet g_reg_sets_arm64[k_num_register_sets] = {
86*b9c1b51eSKate Stone     {"General Purpose Registers", "gpr", k_num_gpr_registers_arm64,
87*b9c1b51eSKate Stone      g_gpr_regnums_arm64},
88*b9c1b51eSKate Stone     {"Floating Point Registers", "fpu", k_num_fpr_registers_arm64,
89*b9c1b51eSKate Stone      g_fpu_regnums_arm64}};
901e209fccSTamas Berghammer 
91068f8a7eSTamas Berghammer NativeRegisterContextLinux *
92*b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
93*b9c1b51eSKate Stone     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
94*b9c1b51eSKate Stone     uint32_t concrete_frame_idx) {
95e85e6021STamas Berghammer   Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS);
96*b9c1b51eSKate Stone   switch (target_arch.GetMachine()) {
97e85e6021STamas Berghammer   case llvm::Triple::arm:
98*b9c1b51eSKate Stone     return new NativeRegisterContextLinux_arm(target_arch, native_thread,
99*b9c1b51eSKate Stone                                               concrete_frame_idx);
100e85e6021STamas Berghammer   case llvm::Triple::aarch64:
101*b9c1b51eSKate Stone     return new NativeRegisterContextLinux_arm64(target_arch, native_thread,
102*b9c1b51eSKate Stone                                                 concrete_frame_idx);
103e85e6021STamas Berghammer   default:
104e85e6021STamas Berghammer     if (log)
105*b9c1b51eSKate Stone       log->Printf("NativeRegisterContextLinux::%s() have no register context "
106*b9c1b51eSKate Stone                   "for architecture: %s\n",
107*b9c1b51eSKate Stone                   __FUNCTION__,
108e85e6021STamas Berghammer                   target_arch.GetTriple().getArchName().str().c_str());
109e85e6021STamas Berghammer     return nullptr;
110e85e6021STamas Berghammer   }
111068f8a7eSTamas Berghammer }
112068f8a7eSTamas Berghammer 
113*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
114*b9c1b51eSKate Stone     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
115*b9c1b51eSKate Stone     uint32_t concrete_frame_idx)
116*b9c1b51eSKate Stone     : NativeRegisterContextLinux(native_thread, concrete_frame_idx,
117*b9c1b51eSKate Stone                                  new RegisterContextLinux_arm64(target_arch)) {
118*b9c1b51eSKate Stone   switch (target_arch.GetMachine()) {
1191e209fccSTamas Berghammer   case llvm::Triple::aarch64:
1201e209fccSTamas Berghammer     m_reg_info.num_registers = k_num_registers_arm64;
1211e209fccSTamas Berghammer     m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64;
1221e209fccSTamas Berghammer     m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64;
1231e209fccSTamas Berghammer     m_reg_info.last_gpr = k_last_gpr_arm64;
1241e209fccSTamas Berghammer     m_reg_info.first_fpr = k_first_fpr_arm64;
1251e209fccSTamas Berghammer     m_reg_info.last_fpr = k_last_fpr_arm64;
1261e209fccSTamas Berghammer     m_reg_info.first_fpr_v = fpu_v0_arm64;
1271e209fccSTamas Berghammer     m_reg_info.last_fpr_v = fpu_v31_arm64;
1281e209fccSTamas Berghammer     m_reg_info.gpr_flags = gpr_cpsr_arm64;
1291e209fccSTamas Berghammer     break;
1301e209fccSTamas Berghammer   default:
1311e209fccSTamas Berghammer     assert(false && "Unhandled target architecture.");
1321e209fccSTamas Berghammer     break;
1331e209fccSTamas Berghammer   }
1341e209fccSTamas Berghammer 
1351e209fccSTamas Berghammer   ::memset(&m_fpr, 0, sizeof(m_fpr));
1361e209fccSTamas Berghammer   ::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64));
137ea8c25a8SOmair Javaid   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
138ea8c25a8SOmair Javaid 
139ea8c25a8SOmair Javaid   // 16 is just a maximum value, query hardware for actual watchpoint count
140ea8c25a8SOmair Javaid   m_max_hwp_supported = 16;
141ea8c25a8SOmair Javaid   m_max_hbp_supported = 16;
142ea8c25a8SOmair Javaid   m_refresh_hwdebug_info = true;
1431e209fccSTamas Berghammer }
1441e209fccSTamas Berghammer 
145*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::GetRegisterSetCount() const {
1461e209fccSTamas Berghammer   return k_num_register_sets;
1471e209fccSTamas Berghammer }
1481e209fccSTamas Berghammer 
149db264a6dSTamas Berghammer const RegisterSet *
150*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetRegisterSet(uint32_t set_index) const {
1511e209fccSTamas Berghammer   if (set_index < k_num_register_sets)
1521e209fccSTamas Berghammer     return &g_reg_sets_arm64[set_index];
1531e209fccSTamas Berghammer 
1541e209fccSTamas Berghammer   return nullptr;
1551e209fccSTamas Berghammer }
1561e209fccSTamas Berghammer 
157*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::GetUserRegisterCount() const {
158cec93c35STamas Berghammer   uint32_t count = 0;
159cec93c35STamas Berghammer   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
160cec93c35STamas Berghammer     count += g_reg_sets_arm64[set_index].num_registers;
161cec93c35STamas Berghammer   return count;
162cec93c35STamas Berghammer }
163cec93c35STamas Berghammer 
164*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadRegister(
165*b9c1b51eSKate Stone     const RegisterInfo *reg_info, RegisterValue &reg_value) {
1661e209fccSTamas Berghammer   Error error;
1671e209fccSTamas Berghammer 
168*b9c1b51eSKate Stone   if (!reg_info) {
1691e209fccSTamas Berghammer     error.SetErrorString("reg_info NULL");
1701e209fccSTamas Berghammer     return error;
1711e209fccSTamas Berghammer   }
1721e209fccSTamas Berghammer 
1731e209fccSTamas Berghammer   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
1741e209fccSTamas Berghammer 
175*b9c1b51eSKate Stone   if (IsFPR(reg)) {
176068f8a7eSTamas Berghammer     error = ReadFPR();
177068f8a7eSTamas Berghammer     if (error.Fail())
1781e209fccSTamas Berghammer       return error;
179*b9c1b51eSKate Stone   } else {
1801e209fccSTamas Berghammer     uint32_t full_reg = reg;
181*b9c1b51eSKate Stone     bool is_subreg = reg_info->invalidate_regs &&
182*b9c1b51eSKate Stone                      (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
1831e209fccSTamas Berghammer 
184*b9c1b51eSKate Stone     if (is_subreg) {
1851e209fccSTamas Berghammer       // Read the full aligned 64-bit register.
1861e209fccSTamas Berghammer       full_reg = reg_info->invalidate_regs[0];
1871e209fccSTamas Berghammer     }
1881e209fccSTamas Berghammer 
1891e209fccSTamas Berghammer     error = ReadRegisterRaw(full_reg, reg_value);
1901e209fccSTamas Berghammer 
191*b9c1b51eSKate Stone     if (error.Success()) {
192*b9c1b51eSKate Stone       // If our read was not aligned (for ah,bh,ch,dh), shift our returned value
193*b9c1b51eSKate Stone       // one byte to the right.
1941e209fccSTamas Berghammer       if (is_subreg && (reg_info->byte_offset & 0x1))
1951e209fccSTamas Berghammer         reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
1961e209fccSTamas Berghammer 
197*b9c1b51eSKate Stone       // If our return byte size was greater than the return value reg size,
198*b9c1b51eSKate Stone       // then
1991e209fccSTamas Berghammer       // use the type specified by reg_info rather than the uint64_t default
2001e209fccSTamas Berghammer       if (reg_value.GetByteSize() > reg_info->byte_size)
2011e209fccSTamas Berghammer         reg_value.SetType(reg_info);
2021e209fccSTamas Berghammer     }
2031e209fccSTamas Berghammer     return error;
2041e209fccSTamas Berghammer   }
2051e209fccSTamas Berghammer 
2061e209fccSTamas Berghammer   // Get pointer to m_fpr variable and set the data from it.
207c40e7b17STamas Berghammer   uint32_t fpr_offset = CalculateFprOffset(reg_info);
208c40e7b17STamas Berghammer   assert(fpr_offset < sizeof m_fpr);
209c40e7b17STamas Berghammer   uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
210*b9c1b51eSKate Stone   reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
211*b9c1b51eSKate Stone                               eByteOrderLittle, error);
2121e209fccSTamas Berghammer 
2131e209fccSTamas Berghammer   return error;
2141e209fccSTamas Berghammer }
2151e209fccSTamas Berghammer 
216*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteRegister(
217*b9c1b51eSKate Stone     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
2181e209fccSTamas Berghammer   if (!reg_info)
2191e209fccSTamas Berghammer     return Error("reg_info NULL");
2201e209fccSTamas Berghammer 
2211e209fccSTamas Berghammer   const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
2221e209fccSTamas Berghammer   if (reg_index == LLDB_INVALID_REGNUM)
223*b9c1b51eSKate Stone     return Error("no lldb regnum for %s", reg_info && reg_info->name
224*b9c1b51eSKate Stone                                               ? reg_info->name
225*b9c1b51eSKate Stone                                               : "<unknown register>");
2261e209fccSTamas Berghammer 
2271e209fccSTamas Berghammer   if (IsGPR(reg_index))
2281e209fccSTamas Berghammer     return WriteRegisterRaw(reg_index, reg_value);
2291e209fccSTamas Berghammer 
230*b9c1b51eSKate Stone   if (IsFPR(reg_index)) {
2311e209fccSTamas Berghammer     // Get pointer to m_fpr variable and set the data to it.
232c40e7b17STamas Berghammer     uint32_t fpr_offset = CalculateFprOffset(reg_info);
233c40e7b17STamas Berghammer     assert(fpr_offset < sizeof m_fpr);
234c40e7b17STamas Berghammer     uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
235*b9c1b51eSKate Stone     switch (reg_info->byte_size) {
2361e209fccSTamas Berghammer     case 2:
2371e209fccSTamas Berghammer       *(uint16_t *)dst = reg_value.GetAsUInt16();
2381e209fccSTamas Berghammer       break;
2391e209fccSTamas Berghammer     case 4:
2401e209fccSTamas Berghammer       *(uint32_t *)dst = reg_value.GetAsUInt32();
2411e209fccSTamas Berghammer       break;
2421e209fccSTamas Berghammer     case 8:
2431e209fccSTamas Berghammer       *(uint64_t *)dst = reg_value.GetAsUInt64();
2441e209fccSTamas Berghammer       break;
2451e209fccSTamas Berghammer     default:
2461e209fccSTamas Berghammer       assert(false && "Unhandled data size.");
247*b9c1b51eSKate Stone       return Error("unhandled register data size %" PRIu32,
248*b9c1b51eSKate Stone                    reg_info->byte_size);
2491e209fccSTamas Berghammer     }
2501e209fccSTamas Berghammer 
251068f8a7eSTamas Berghammer     Error error = WriteFPR();
252068f8a7eSTamas Berghammer     if (error.Fail())
253068f8a7eSTamas Berghammer       return error;
2541e209fccSTamas Berghammer 
2551e209fccSTamas Berghammer     return Error();
2561e209fccSTamas Berghammer   }
2571e209fccSTamas Berghammer 
258*b9c1b51eSKate Stone   return Error("failed - register wasn't recognized to be a GPR or an FPR, "
259*b9c1b51eSKate Stone                "write strategy unknown");
2601e209fccSTamas Berghammer }
2611e209fccSTamas Berghammer 
262*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
263*b9c1b51eSKate Stone     lldb::DataBufferSP &data_sp) {
2641e209fccSTamas Berghammer   Error error;
2651e209fccSTamas Berghammer 
266db264a6dSTamas Berghammer   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
2671e209fccSTamas Berghammer   if (!data_sp)
268*b9c1b51eSKate Stone     return Error("failed to allocate DataBufferHeap instance of size %" PRIu64,
269*b9c1b51eSKate Stone                  REG_CONTEXT_SIZE);
2701e209fccSTamas Berghammer 
271068f8a7eSTamas Berghammer   error = ReadGPR();
272068f8a7eSTamas Berghammer   if (error.Fail())
2731e209fccSTamas Berghammer     return error;
2741e209fccSTamas Berghammer 
275068f8a7eSTamas Berghammer   error = ReadFPR();
276068f8a7eSTamas Berghammer   if (error.Fail())
2771e209fccSTamas Berghammer     return error;
2781e209fccSTamas Berghammer 
2791e209fccSTamas Berghammer   uint8_t *dst = data_sp->GetBytes();
280*b9c1b51eSKate Stone   if (dst == nullptr) {
281*b9c1b51eSKate Stone     error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
282*b9c1b51eSKate Stone                                    " returned a null pointer",
283*b9c1b51eSKate Stone                                    REG_CONTEXT_SIZE);
2841e209fccSTamas Berghammer     return error;
2851e209fccSTamas Berghammer   }
2861e209fccSTamas Berghammer 
2871e209fccSTamas Berghammer   ::memcpy(dst, &m_gpr_arm64, GetGPRSize());
2881e209fccSTamas Berghammer   dst += GetGPRSize();
2891e209fccSTamas Berghammer   ::memcpy(dst, &m_fpr, sizeof(m_fpr));
2901e209fccSTamas Berghammer 
2911e209fccSTamas Berghammer   return error;
2921e209fccSTamas Berghammer }
2931e209fccSTamas Berghammer 
294*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
295*b9c1b51eSKate Stone     const lldb::DataBufferSP &data_sp) {
2961e209fccSTamas Berghammer   Error error;
2971e209fccSTamas Berghammer 
298*b9c1b51eSKate Stone   if (!data_sp) {
299*b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
300*b9c1b51eSKate Stone         "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided",
301*b9c1b51eSKate Stone         __FUNCTION__);
3021e209fccSTamas Berghammer     return error;
3031e209fccSTamas Berghammer   }
3041e209fccSTamas Berghammer 
305*b9c1b51eSKate Stone   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
306*b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
307*b9c1b51eSKate Stone         "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched "
308*b9c1b51eSKate Stone         "data size, expected %" PRIu64 ", actual %" PRIu64,
309*b9c1b51eSKate Stone         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
3101e209fccSTamas Berghammer     return error;
3111e209fccSTamas Berghammer   }
3121e209fccSTamas Berghammer 
3131e209fccSTamas Berghammer   uint8_t *src = data_sp->GetBytes();
314*b9c1b51eSKate Stone   if (src == nullptr) {
315*b9c1b51eSKate Stone     error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s "
316*b9c1b51eSKate Stone                                    "DataBuffer::GetBytes() returned a null "
317*b9c1b51eSKate Stone                                    "pointer",
318*b9c1b51eSKate Stone                                    __FUNCTION__);
3191e209fccSTamas Berghammer     return error;
3201e209fccSTamas Berghammer   }
3211e209fccSTamas Berghammer   ::memcpy(&m_gpr_arm64, src, GetRegisterInfoInterface().GetGPRSize());
3221e209fccSTamas Berghammer 
323068f8a7eSTamas Berghammer   error = WriteGPR();
324068f8a7eSTamas Berghammer   if (error.Fail())
3251e209fccSTamas Berghammer     return error;
3261e209fccSTamas Berghammer 
3271e209fccSTamas Berghammer   src += GetRegisterInfoInterface().GetGPRSize();
3281e209fccSTamas Berghammer   ::memcpy(&m_fpr, src, sizeof(m_fpr));
3291e209fccSTamas Berghammer 
330068f8a7eSTamas Berghammer   error = WriteFPR();
3311e209fccSTamas Berghammer   if (error.Fail())
3321e209fccSTamas Berghammer     return error;
3331e209fccSTamas Berghammer 
3341e209fccSTamas Berghammer   return error;
3351e209fccSTamas Berghammer }
3361e209fccSTamas Berghammer 
337*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const {
3381e209fccSTamas Berghammer   return reg <= m_reg_info.last_gpr; // GPR's come first.
3391e209fccSTamas Berghammer }
3401e209fccSTamas Berghammer 
341*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const {
3421e209fccSTamas Berghammer   return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
3431e209fccSTamas Berghammer }
3441e209fccSTamas Berghammer 
345ea8c25a8SOmair Javaid uint32_t
346*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::SetHardwareBreakpoint(lldb::addr_t addr,
347*b9c1b51eSKate Stone                                                         size_t size) {
348ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
349ea8c25a8SOmair Javaid 
350ea8c25a8SOmair Javaid   if (log)
351ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
352ea8c25a8SOmair Javaid 
3533a56363aSOmair Javaid   Error error;
354ea8c25a8SOmair Javaid 
3553a56363aSOmair Javaid   // Read hardware breakpoint and watchpoint information.
3563a56363aSOmair Javaid   error = ReadHardwareDebugInfo();
3573a56363aSOmair Javaid 
3583a56363aSOmair Javaid   if (error.Fail())
3593a56363aSOmair Javaid     return LLDB_INVALID_INDEX32;
3603a56363aSOmair Javaid 
3613a56363aSOmair Javaid   uint32_t control_value = 0, bp_index = 0;
362ea8c25a8SOmair Javaid 
363ea8c25a8SOmair Javaid   // Check if size has a valid hardware breakpoint length.
364ea8c25a8SOmair Javaid   if (size != 4)
365*b9c1b51eSKate Stone     return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware
366*b9c1b51eSKate Stone                                  // breakpoint
367ea8c25a8SOmair Javaid 
368ea8c25a8SOmair Javaid   // Check 4-byte alignment for hardware breakpoint target address.
369ea8c25a8SOmair Javaid   if (addr & 0x03)
370ea8c25a8SOmair Javaid     return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
371ea8c25a8SOmair Javaid 
372ea8c25a8SOmair Javaid   // Setup control value
373ea8c25a8SOmair Javaid   control_value = 0;
374ea8c25a8SOmair Javaid   control_value |= ((1 << size) - 1) << 5;
375ea8c25a8SOmair Javaid   control_value |= (2 << 1) | 1;
376ea8c25a8SOmair Javaid 
377ea8c25a8SOmair Javaid   // Iterate over stored hardware breakpoints
378ea8c25a8SOmair Javaid   // Find a free bp_index or update reference count if duplicate.
379ea8c25a8SOmair Javaid   bp_index = LLDB_INVALID_INDEX32;
380*b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
381*b9c1b51eSKate Stone     if ((m_hbr_regs[i].control & 1) == 0) {
382ea8c25a8SOmair Javaid       bp_index = i; // Mark last free slot
383*b9c1b51eSKate Stone     } else if (m_hbr_regs[i].address == addr &&
384*b9c1b51eSKate Stone                m_hbr_regs[i].control == control_value) {
385ea8c25a8SOmair Javaid       bp_index = i; // Mark duplicate index
386ea8c25a8SOmair Javaid       break;        // Stop searching here
387ea8c25a8SOmair Javaid     }
388ea8c25a8SOmair Javaid   }
389ea8c25a8SOmair Javaid 
390ea8c25a8SOmair Javaid   if (bp_index == LLDB_INVALID_INDEX32)
391ea8c25a8SOmair Javaid     return LLDB_INVALID_INDEX32;
392ea8c25a8SOmair Javaid 
393f24741d9SOmair Javaid   // Add new or update existing breakpoint
394*b9c1b51eSKate Stone   if ((m_hbr_regs[bp_index].control & 1) == 0) {
395ea8c25a8SOmair Javaid     m_hbr_regs[bp_index].address = addr;
396ea8c25a8SOmair Javaid     m_hbr_regs[bp_index].control = control_value;
397ea8c25a8SOmair Javaid     m_hbr_regs[bp_index].refcount = 1;
398ea8c25a8SOmair Javaid 
3991fd2a8cfSOmair Javaid     // PTRACE call to set corresponding hardware breakpoint register.
4003a56363aSOmair Javaid     error = WriteHardwareDebugRegs(eDREGTypeBREAK);
4013a56363aSOmair Javaid 
402*b9c1b51eSKate Stone     if (error.Fail()) {
403f24741d9SOmair Javaid       m_hbr_regs[bp_index].address = 0;
404f24741d9SOmair Javaid       m_hbr_regs[bp_index].control &= ~1;
405f24741d9SOmair Javaid       m_hbr_regs[bp_index].refcount = 0;
406f24741d9SOmair Javaid 
4073a56363aSOmair Javaid       return LLDB_INVALID_INDEX32;
408ea8c25a8SOmair Javaid     }
409*b9c1b51eSKate Stone   } else
410ea8c25a8SOmair Javaid     m_hbr_regs[bp_index].refcount++;
411ea8c25a8SOmair Javaid 
412ea8c25a8SOmair Javaid   return bp_index;
413ea8c25a8SOmair Javaid }
414ea8c25a8SOmair Javaid 
415*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint(
416*b9c1b51eSKate Stone     uint32_t hw_idx) {
417ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
418ea8c25a8SOmair Javaid 
419ea8c25a8SOmair Javaid   if (log)
420ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
421ea8c25a8SOmair Javaid 
4223a56363aSOmair Javaid   Error error;
4233a56363aSOmair Javaid 
4241fd2a8cfSOmair Javaid   // Read hardware breakpoint and watchpoint information.
4253a56363aSOmair Javaid   error = ReadHardwareDebugInfo();
4263a56363aSOmair Javaid 
4273a56363aSOmair Javaid   if (error.Fail())
4283a56363aSOmair Javaid     return false;
4291fd2a8cfSOmair Javaid 
430ea8c25a8SOmair Javaid   if (hw_idx >= m_max_hbp_supported)
431ea8c25a8SOmair Javaid     return false;
432ea8c25a8SOmair Javaid 
433ea8c25a8SOmair Javaid   // Update reference count if multiple references.
434*b9c1b51eSKate Stone   if (m_hbr_regs[hw_idx].refcount > 1) {
435ea8c25a8SOmair Javaid     m_hbr_regs[hw_idx].refcount--;
436ea8c25a8SOmair Javaid     return true;
437*b9c1b51eSKate Stone   } else if (m_hbr_regs[hw_idx].refcount == 1) {
438f24741d9SOmair Javaid     // Create a backup we can revert to in case of failure.
439f24741d9SOmair Javaid     lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
440f24741d9SOmair Javaid     uint32_t tempControl = m_hbr_regs[hw_idx].control;
441f24741d9SOmair Javaid     uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount;
442f24741d9SOmair Javaid 
443ea8c25a8SOmair Javaid     m_hbr_regs[hw_idx].control &= ~1;
444ea8c25a8SOmair Javaid     m_hbr_regs[hw_idx].address = 0;
445ea8c25a8SOmair Javaid     m_hbr_regs[hw_idx].refcount = 0;
446ea8c25a8SOmair Javaid 
4471fd2a8cfSOmair Javaid     // PTRACE call to clear corresponding hardware breakpoint register.
4481fd2a8cfSOmair Javaid     WriteHardwareDebugRegs(eDREGTypeBREAK);
4493a56363aSOmair Javaid 
450*b9c1b51eSKate Stone     if (error.Fail()) {
451f24741d9SOmair Javaid       m_hbr_regs[hw_idx].control = tempControl;
452f24741d9SOmair Javaid       m_hbr_regs[hw_idx].address = tempAddr;
453f24741d9SOmair Javaid       m_hbr_regs[hw_idx].refcount = tempRefCount;
454f24741d9SOmair Javaid 
4553a56363aSOmair Javaid       return false;
456f24741d9SOmair Javaid     }
4573a56363aSOmair Javaid 
4583a56363aSOmair Javaid     return true;
459ea8c25a8SOmair Javaid   }
460ea8c25a8SOmair Javaid 
461ea8c25a8SOmair Javaid   return false;
462ea8c25a8SOmair Javaid }
463ea8c25a8SOmair Javaid 
464*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints() {
465ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
466ea8c25a8SOmair Javaid 
467ea8c25a8SOmair Javaid   if (log)
468ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
469ea8c25a8SOmair Javaid 
4703a56363aSOmair Javaid   Error error;
4713a56363aSOmair Javaid 
4721fd2a8cfSOmair Javaid   // Read hardware breakpoint and watchpoint information.
4733a56363aSOmair Javaid   error = ReadHardwareDebugInfo();
4743a56363aSOmair Javaid 
4753a56363aSOmair Javaid   if (error.Fail())
47662661473SOmair Javaid     return 0;
4771fd2a8cfSOmair Javaid 
478ea8c25a8SOmair Javaid   return m_max_hwp_supported;
479ea8c25a8SOmair Javaid }
480ea8c25a8SOmair Javaid 
481*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::SetHardwareWatchpoint(
482*b9c1b51eSKate Stone     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
483ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
484ea8c25a8SOmair Javaid 
485ea8c25a8SOmair Javaid   if (log)
486ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
487ea8c25a8SOmair Javaid 
4883a56363aSOmair Javaid   Error error;
489ea8c25a8SOmair Javaid 
4903a56363aSOmair Javaid   // Read hardware breakpoint and watchpoint information.
4913a56363aSOmair Javaid   error = ReadHardwareDebugInfo();
4923a56363aSOmair Javaid 
4933a56363aSOmair Javaid   if (error.Fail())
4943a56363aSOmair Javaid     return LLDB_INVALID_INDEX32;
4953a56363aSOmair Javaid 
4963a56363aSOmair Javaid   uint32_t control_value = 0, wp_index = 0;
49743507f57SOmair Javaid   lldb::addr_t real_addr = addr;
498ea8c25a8SOmair Javaid 
4991fd2a8cfSOmair Javaid   // Check if we are setting watchpoint other than read/write/access
5001fd2a8cfSOmair Javaid   // Also update watchpoint flag to match AArch64 write-read bit configuration.
501*b9c1b51eSKate Stone   switch (watch_flags) {
5021fd2a8cfSOmair Javaid   case 1:
5031fd2a8cfSOmair Javaid     watch_flags = 2;
5041fd2a8cfSOmair Javaid     break;
5051fd2a8cfSOmair Javaid   case 2:
5061fd2a8cfSOmair Javaid     watch_flags = 1;
5071fd2a8cfSOmair Javaid     break;
5081fd2a8cfSOmair Javaid   case 3:
5091fd2a8cfSOmair Javaid     break;
5101fd2a8cfSOmair Javaid   default:
5111fd2a8cfSOmair Javaid     return LLDB_INVALID_INDEX32;
5121fd2a8cfSOmair Javaid   }
513ea8c25a8SOmair Javaid 
514ea8c25a8SOmair Javaid   // Check if size has a valid hardware watchpoint length.
515ea8c25a8SOmair Javaid   if (size != 1 && size != 2 && size != 4 && size != 8)
5161fd2a8cfSOmair Javaid     return LLDB_INVALID_INDEX32;
517ea8c25a8SOmair Javaid 
518ea8c25a8SOmair Javaid   // Check 8-byte alignment for hardware watchpoint target address.
51943507f57SOmair Javaid   // Below is a hack to recalculate address and size in order to
52043507f57SOmair Javaid   // make sure we can watch non 8-byte alligned addresses as well.
521*b9c1b51eSKate Stone   if (addr & 0x07) {
52243507f57SOmair Javaid     uint8_t watch_mask = (addr & 0x07) + size;
52343507f57SOmair Javaid 
52443507f57SOmair Javaid     if (watch_mask > 0x08)
5251fd2a8cfSOmair Javaid       return LLDB_INVALID_INDEX32;
52643507f57SOmair Javaid     else if (watch_mask <= 0x02)
52743507f57SOmair Javaid       size = 2;
52843507f57SOmair Javaid     else if (watch_mask <= 0x04)
52943507f57SOmair Javaid       size = 4;
53043507f57SOmair Javaid     else
53143507f57SOmair Javaid       size = 8;
53243507f57SOmair Javaid 
53343507f57SOmair Javaid     addr = addr & (~0x07);
53443507f57SOmair Javaid   }
535ea8c25a8SOmair Javaid 
536ea8c25a8SOmair Javaid   // Setup control value
537ea8c25a8SOmair Javaid   control_value = watch_flags << 3;
538ea8c25a8SOmair Javaid   control_value |= ((1 << size) - 1) << 5;
539ea8c25a8SOmair Javaid   control_value |= (2 << 1) | 1;
540ea8c25a8SOmair Javaid 
541ea8c25a8SOmair Javaid   // Iterate over stored watchpoints
542ea8c25a8SOmair Javaid   // Find a free wp_index or update reference count if duplicate.
543ea8c25a8SOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
544*b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
545*b9c1b51eSKate Stone     if ((m_hwp_regs[i].control & 1) == 0) {
546ea8c25a8SOmair Javaid       wp_index = i; // Mark last free slot
547*b9c1b51eSKate Stone     } else if (m_hwp_regs[i].address == addr &&
548*b9c1b51eSKate Stone                m_hwp_regs[i].control == control_value) {
549ea8c25a8SOmair Javaid       wp_index = i; // Mark duplicate index
550ea8c25a8SOmair Javaid       break;        // Stop searching here
551ea8c25a8SOmair Javaid     }
552ea8c25a8SOmair Javaid   }
553ea8c25a8SOmair Javaid 
554ea8c25a8SOmair Javaid   if (wp_index == LLDB_INVALID_INDEX32)
555ea8c25a8SOmair Javaid     return LLDB_INVALID_INDEX32;
556ea8c25a8SOmair Javaid 
557ea8c25a8SOmair Javaid   // Add new or update existing watchpoint
558*b9c1b51eSKate Stone   if ((m_hwp_regs[wp_index].control & 1) == 0) {
5591fd2a8cfSOmair Javaid     // Update watchpoint in local cache
56043507f57SOmair Javaid     m_hwp_regs[wp_index].real_addr = real_addr;
561ea8c25a8SOmair Javaid     m_hwp_regs[wp_index].address = addr;
562ea8c25a8SOmair Javaid     m_hwp_regs[wp_index].control = control_value;
563ea8c25a8SOmair Javaid     m_hwp_regs[wp_index].refcount = 1;
564ea8c25a8SOmair Javaid 
565ea8c25a8SOmair Javaid     // PTRACE call to set corresponding watchpoint register.
5663a56363aSOmair Javaid     error = WriteHardwareDebugRegs(eDREGTypeWATCH);
5673a56363aSOmair Javaid 
568*b9c1b51eSKate Stone     if (error.Fail()) {
569f24741d9SOmair Javaid       m_hwp_regs[wp_index].address = 0;
570f24741d9SOmair Javaid       m_hwp_regs[wp_index].control &= ~1;
571f24741d9SOmair Javaid       m_hwp_regs[wp_index].refcount = 0;
572f24741d9SOmair Javaid 
5733a56363aSOmair Javaid       return LLDB_INVALID_INDEX32;
574ea8c25a8SOmair Javaid     }
575*b9c1b51eSKate Stone   } else
576ea8c25a8SOmair Javaid     m_hwp_regs[wp_index].refcount++;
577ea8c25a8SOmair Javaid 
578ea8c25a8SOmair Javaid   return wp_index;
579ea8c25a8SOmair Javaid }
580ea8c25a8SOmair Javaid 
581*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint(
582*b9c1b51eSKate Stone     uint32_t wp_index) {
583ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
584ea8c25a8SOmair Javaid 
585ea8c25a8SOmair Javaid   if (log)
586ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
587ea8c25a8SOmair Javaid 
5883a56363aSOmair Javaid   Error error;
5893a56363aSOmair Javaid 
5901fd2a8cfSOmair Javaid   // Read hardware breakpoint and watchpoint information.
5913a56363aSOmair Javaid   error = ReadHardwareDebugInfo();
5923a56363aSOmair Javaid 
5933a56363aSOmair Javaid   if (error.Fail())
5943a56363aSOmair Javaid     return false;
595ea8c25a8SOmair Javaid 
596ea8c25a8SOmair Javaid   if (wp_index >= m_max_hwp_supported)
597ea8c25a8SOmair Javaid     return false;
598ea8c25a8SOmair Javaid 
599ea8c25a8SOmair Javaid   // Update reference count if multiple references.
600*b9c1b51eSKate Stone   if (m_hwp_regs[wp_index].refcount > 1) {
601ea8c25a8SOmair Javaid     m_hwp_regs[wp_index].refcount--;
602ea8c25a8SOmair Javaid     return true;
603*b9c1b51eSKate Stone   } else if (m_hwp_regs[wp_index].refcount == 1) {
604f24741d9SOmair Javaid     // Create a backup we can revert to in case of failure.
605f24741d9SOmair Javaid     lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
606f24741d9SOmair Javaid     uint32_t tempControl = m_hwp_regs[wp_index].control;
607f24741d9SOmair Javaid     uint32_t tempRefCount = m_hwp_regs[wp_index].refcount;
608f24741d9SOmair Javaid 
6091fd2a8cfSOmair Javaid     // Update watchpoint in local cache
610ea8c25a8SOmair Javaid     m_hwp_regs[wp_index].control &= ~1;
611ea8c25a8SOmair Javaid     m_hwp_regs[wp_index].address = 0;
612ea8c25a8SOmair Javaid     m_hwp_regs[wp_index].refcount = 0;
613ea8c25a8SOmair Javaid 
6141fd2a8cfSOmair Javaid     // Ptrace call to update hardware debug registers
6153a56363aSOmair Javaid     error = WriteHardwareDebugRegs(eDREGTypeWATCH);
6163a56363aSOmair Javaid 
617*b9c1b51eSKate Stone     if (error.Fail()) {
618f24741d9SOmair Javaid       m_hwp_regs[wp_index].control = tempControl;
619f24741d9SOmair Javaid       m_hwp_regs[wp_index].address = tempAddr;
620f24741d9SOmair Javaid       m_hwp_regs[wp_index].refcount = tempRefCount;
621f24741d9SOmair Javaid 
6223a56363aSOmair Javaid       return false;
623f24741d9SOmair Javaid     }
6243a56363aSOmair Javaid 
625ea8c25a8SOmair Javaid     return true;
626ea8c25a8SOmair Javaid   }
627ea8c25a8SOmair Javaid 
628ea8c25a8SOmair Javaid   return false;
629ea8c25a8SOmair Javaid }
630ea8c25a8SOmair Javaid 
631*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints() {
632ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
633ea8c25a8SOmair Javaid 
634ea8c25a8SOmair Javaid   if (log)
635ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
636ea8c25a8SOmair Javaid 
6373a56363aSOmair Javaid   Error error;
6383a56363aSOmair Javaid 
6391fd2a8cfSOmair Javaid   // Read hardware breakpoint and watchpoint information.
6403a56363aSOmair Javaid   error = ReadHardwareDebugInfo();
6413a56363aSOmair Javaid 
6423a56363aSOmair Javaid   if (error.Fail())
6433a56363aSOmair Javaid     return error;
644ea8c25a8SOmair Javaid 
645f24741d9SOmair Javaid   lldb::addr_t tempAddr = 0;
646f24741d9SOmair Javaid   uint32_t tempControl = 0, tempRefCount = 0;
647f24741d9SOmair Javaid 
648*b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
649*b9c1b51eSKate Stone     if (m_hwp_regs[i].control & 0x01) {
650f24741d9SOmair Javaid       // Create a backup we can revert to in case of failure.
651f24741d9SOmair Javaid       tempAddr = m_hwp_regs[i].address;
652f24741d9SOmair Javaid       tempControl = m_hwp_regs[i].control;
653f24741d9SOmair Javaid       tempRefCount = m_hwp_regs[i].refcount;
654f24741d9SOmair Javaid 
6551fd2a8cfSOmair Javaid       // Clear watchpoints in local cache
656ea8c25a8SOmair Javaid       m_hwp_regs[i].control &= ~1;
657ea8c25a8SOmair Javaid       m_hwp_regs[i].address = 0;
658ea8c25a8SOmair Javaid       m_hwp_regs[i].refcount = 0;
659ea8c25a8SOmair Javaid 
6601fd2a8cfSOmair Javaid       // Ptrace call to update hardware debug registers
6613a56363aSOmair Javaid       error = WriteHardwareDebugRegs(eDREGTypeWATCH);
6623a56363aSOmair Javaid 
663*b9c1b51eSKate Stone       if (error.Fail()) {
664f24741d9SOmair Javaid         m_hwp_regs[i].control = tempControl;
665f24741d9SOmair Javaid         m_hwp_regs[i].address = tempAddr;
666f24741d9SOmair Javaid         m_hwp_regs[i].refcount = tempRefCount;
667f24741d9SOmair Javaid 
6683a56363aSOmair Javaid         return error;
669ea8c25a8SOmair Javaid       }
670ea8c25a8SOmair Javaid     }
671f24741d9SOmair Javaid   }
672ea8c25a8SOmair Javaid 
673ea8c25a8SOmair Javaid   return Error();
674ea8c25a8SOmair Javaid }
675ea8c25a8SOmair Javaid 
676ea8c25a8SOmair Javaid uint32_t
677*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) {
678ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
679ea8c25a8SOmair Javaid 
680ea8c25a8SOmair Javaid   if (log)
681ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
682*b9c1b51eSKate Stone   switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) {
683ea8c25a8SOmair Javaid   case 0x01:
684ea8c25a8SOmair Javaid     return 1;
685ea8c25a8SOmair Javaid   case 0x03:
686ea8c25a8SOmair Javaid     return 2;
687ea8c25a8SOmair Javaid   case 0x0f:
688ea8c25a8SOmair Javaid     return 4;
689ea8c25a8SOmair Javaid   case 0xff:
690ea8c25a8SOmair Javaid     return 8;
691ea8c25a8SOmair Javaid   default:
692ea8c25a8SOmair Javaid     return 0;
693ea8c25a8SOmair Javaid   }
694ea8c25a8SOmair Javaid }
695*b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) {
696ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
697ea8c25a8SOmair Javaid 
698ea8c25a8SOmair Javaid   if (log)
699ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
700ea8c25a8SOmair Javaid 
701ea8c25a8SOmair Javaid   if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
702ea8c25a8SOmair Javaid     return true;
703ea8c25a8SOmair Javaid   else
704ea8c25a8SOmair Javaid     return false;
705ea8c25a8SOmair Javaid }
706ea8c25a8SOmair Javaid 
707*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(
708*b9c1b51eSKate Stone     uint32_t &wp_index, lldb::addr_t trap_addr) {
709ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
710ea8c25a8SOmair Javaid 
711ea8c25a8SOmair Javaid   if (log)
712ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
713ea8c25a8SOmair Javaid 
714ea8c25a8SOmair Javaid   uint32_t watch_size;
715ea8c25a8SOmair Javaid   lldb::addr_t watch_addr;
716ea8c25a8SOmair Javaid 
717*b9c1b51eSKate Stone   for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
718ea8c25a8SOmair Javaid     watch_size = GetWatchpointSize(wp_index);
719ea8c25a8SOmair Javaid     watch_addr = m_hwp_regs[wp_index].address;
720ea8c25a8SOmair Javaid 
721*b9c1b51eSKate Stone     if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) &&
722*b9c1b51eSKate Stone         trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) {
72343507f57SOmair Javaid       m_hwp_regs[wp_index].hit_addr = trap_addr;
724ea8c25a8SOmair Javaid       return Error();
725ea8c25a8SOmair Javaid     }
726ea8c25a8SOmair Javaid   }
727ea8c25a8SOmair Javaid 
728ea8c25a8SOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
729ea8c25a8SOmair Javaid   return Error();
730ea8c25a8SOmair Javaid }
731ea8c25a8SOmair Javaid 
732ea8c25a8SOmair Javaid lldb::addr_t
733*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointAddress(uint32_t wp_index) {
734ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
735ea8c25a8SOmair Javaid 
736ea8c25a8SOmair Javaid   if (log)
737ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
738ea8c25a8SOmair Javaid 
739ea8c25a8SOmair Javaid   if (wp_index >= m_max_hwp_supported)
740ea8c25a8SOmair Javaid     return LLDB_INVALID_ADDRESS;
741ea8c25a8SOmair Javaid 
742ea8c25a8SOmair Javaid   if (WatchpointIsEnabled(wp_index))
74343507f57SOmair Javaid     return m_hwp_regs[wp_index].real_addr;
74443507f57SOmair Javaid   else
74543507f57SOmair Javaid     return LLDB_INVALID_ADDRESS;
74643507f57SOmair Javaid }
74743507f57SOmair Javaid 
74843507f57SOmair Javaid lldb::addr_t
749*b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointHitAddress(uint32_t wp_index) {
75043507f57SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
75143507f57SOmair Javaid 
75243507f57SOmair Javaid   if (log)
75343507f57SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
75443507f57SOmair Javaid 
75543507f57SOmair Javaid   if (wp_index >= m_max_hwp_supported)
75643507f57SOmair Javaid     return LLDB_INVALID_ADDRESS;
75743507f57SOmair Javaid 
75843507f57SOmair Javaid   if (WatchpointIsEnabled(wp_index))
75943507f57SOmair Javaid     return m_hwp_regs[wp_index].hit_addr;
760ea8c25a8SOmair Javaid   else
761ea8c25a8SOmair Javaid     return LLDB_INVALID_ADDRESS;
762ea8c25a8SOmair Javaid }
763ea8c25a8SOmair Javaid 
764*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
765*b9c1b51eSKate Stone   if (!m_refresh_hwdebug_info) {
7661fd2a8cfSOmair Javaid     return Error();
7671fd2a8cfSOmair Javaid   }
7681fd2a8cfSOmair Javaid 
769c7512fdcSPavel Labath   ::pid_t tid = m_thread.GetID();
770ea8c25a8SOmair Javaid 
771c7512fdcSPavel Labath   int regset = NT_ARM_HW_WATCH;
772c7512fdcSPavel Labath   struct iovec ioVec;
773c7512fdcSPavel Labath   struct user_hwdebug_state dreg_state;
774c7512fdcSPavel Labath   Error error;
775c7512fdcSPavel Labath 
776c7512fdcSPavel Labath   ioVec.iov_base = &dreg_state;
777c7512fdcSPavel Labath   ioVec.iov_len = sizeof(dreg_state);
778*b9c1b51eSKate Stone   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
779*b9c1b51eSKate Stone                                             &ioVec, ioVec.iov_len);
7803a56363aSOmair Javaid 
7813a56363aSOmair Javaid   if (error.Fail())
7823a56363aSOmair Javaid     return error;
7833a56363aSOmair Javaid 
7841fd2a8cfSOmair Javaid   m_max_hwp_supported = dreg_state.dbg_info & 0xff;
785c7512fdcSPavel Labath 
786c7512fdcSPavel Labath   regset = NT_ARM_HW_BREAK;
787*b9c1b51eSKate Stone   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
788*b9c1b51eSKate Stone                                             &ioVec, ioVec.iov_len);
7891fd2a8cfSOmair Javaid 
7903a56363aSOmair Javaid   if (error.Fail())
7913a56363aSOmair Javaid     return error;
7923a56363aSOmair Javaid 
7933a56363aSOmair Javaid   m_max_hbp_supported = dreg_state.dbg_info & 0xff;
7941fd2a8cfSOmair Javaid   m_refresh_hwdebug_info = false;
795c7512fdcSPavel Labath 
796c7512fdcSPavel Labath   return error;
797ea8c25a8SOmair Javaid }
798068f8a7eSTamas Berghammer 
799*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) {
800c7512fdcSPavel Labath   struct iovec ioVec;
801c7512fdcSPavel Labath   struct user_hwdebug_state dreg_state;
802c7512fdcSPavel Labath   Error error;
803c7512fdcSPavel Labath 
804c7512fdcSPavel Labath   memset(&dreg_state, 0, sizeof(dreg_state));
805c7512fdcSPavel Labath   ioVec.iov_base = &dreg_state;
806c7512fdcSPavel Labath 
807*b9c1b51eSKate Stone   if (hwbType == eDREGTypeWATCH) {
8081fd2a8cfSOmair Javaid     hwbType = NT_ARM_HW_WATCH;
809*b9c1b51eSKate Stone     ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
810*b9c1b51eSKate Stone                     (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
8111fd2a8cfSOmair Javaid 
812*b9c1b51eSKate Stone     for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
8131fd2a8cfSOmair Javaid       dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
8141fd2a8cfSOmair Javaid       dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
8151fd2a8cfSOmair Javaid     }
816*b9c1b51eSKate Stone   } else {
8171fd2a8cfSOmair Javaid     hwbType = NT_ARM_HW_BREAK;
818*b9c1b51eSKate Stone     ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
819*b9c1b51eSKate Stone                     (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
8201fd2a8cfSOmair Javaid 
821*b9c1b51eSKate Stone     for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
8221fd2a8cfSOmair Javaid       dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address;
8231fd2a8cfSOmair Javaid       dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control;
8241fd2a8cfSOmair Javaid     }
825068f8a7eSTamas Berghammer   }
826068f8a7eSTamas Berghammer 
827*b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
828*b9c1b51eSKate Stone                                            &hwbType, &ioVec, ioVec.iov_len);
829c7512fdcSPavel Labath }
830c7512fdcSPavel Labath 
831*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadRegisterValue(
832*b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, uint32_t size,
833*b9c1b51eSKate Stone     RegisterValue &value) {
834c7512fdcSPavel Labath   Error error;
835*b9c1b51eSKate Stone   if (offset > sizeof(struct user_pt_regs)) {
836c7512fdcSPavel Labath     uintptr_t offset = offset - sizeof(struct user_pt_regs);
837*b9c1b51eSKate Stone     if (offset > sizeof(struct user_fpsimd_state)) {
838c7512fdcSPavel Labath       error.SetErrorString("invalid offset value");
839c7512fdcSPavel Labath       return error;
840c7512fdcSPavel Labath     }
841c7512fdcSPavel Labath     elf_fpregset_t regs;
842c7512fdcSPavel Labath     int regset = NT_FPREGSET;
843c7512fdcSPavel Labath     struct iovec ioVec;
844c7512fdcSPavel Labath 
845c7512fdcSPavel Labath     ioVec.iov_base = &regs;
846c7512fdcSPavel Labath     ioVec.iov_len = sizeof regs;
8474a9babb2SPavel Labath     error = NativeProcessLinux::PtraceWrapper(
8484a9babb2SPavel Labath         PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
849*b9c1b51eSKate Stone     if (error.Success()) {
850c7512fdcSPavel Labath       ArchSpec arch;
851c7512fdcSPavel Labath       if (m_thread.GetProcess()->GetArchitecture(arch))
852*b9c1b51eSKate Stone         value.SetBytes((void *)(((unsigned char *)(&regs)) + offset), 16,
853*b9c1b51eSKate Stone                        arch.GetByteOrder());
854c7512fdcSPavel Labath       else
855c7512fdcSPavel Labath         error.SetErrorString("failed to get architecture");
856c7512fdcSPavel Labath     }
857*b9c1b51eSKate Stone   } else {
858c7512fdcSPavel Labath     elf_gregset_t regs;
859c7512fdcSPavel Labath     int regset = NT_PRSTATUS;
860c7512fdcSPavel Labath     struct iovec ioVec;
861c7512fdcSPavel Labath 
862c7512fdcSPavel Labath     ioVec.iov_base = &regs;
863c7512fdcSPavel Labath     ioVec.iov_len = sizeof regs;
8644a9babb2SPavel Labath     error = NativeProcessLinux::PtraceWrapper(
8654a9babb2SPavel Labath         PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
866*b9c1b51eSKate Stone     if (error.Success()) {
867c7512fdcSPavel Labath       ArchSpec arch;
868c7512fdcSPavel Labath       if (m_thread.GetProcess()->GetArchitecture(arch))
869*b9c1b51eSKate Stone         value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8,
870*b9c1b51eSKate Stone                        arch.GetByteOrder());
871c7512fdcSPavel Labath       else
872c7512fdcSPavel Labath         error.SetErrorString("failed to get architecture");
873c7512fdcSPavel Labath     }
874c7512fdcSPavel Labath   }
875c7512fdcSPavel Labath   return error;
876068f8a7eSTamas Berghammer }
877068f8a7eSTamas Berghammer 
878*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteRegisterValue(
879*b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, const RegisterValue &value) {
880c7512fdcSPavel Labath   Error error;
881c7512fdcSPavel Labath   ::pid_t tid = m_thread.GetID();
882*b9c1b51eSKate Stone   if (offset > sizeof(struct user_pt_regs)) {
883c7512fdcSPavel Labath     uintptr_t offset = offset - sizeof(struct user_pt_regs);
884*b9c1b51eSKate Stone     if (offset > sizeof(struct user_fpsimd_state)) {
885c7512fdcSPavel Labath       error.SetErrorString("invalid offset value");
886c7512fdcSPavel Labath       return error;
887c7512fdcSPavel Labath     }
888c7512fdcSPavel Labath     elf_fpregset_t regs;
889c7512fdcSPavel Labath     int regset = NT_FPREGSET;
890c7512fdcSPavel Labath     struct iovec ioVec;
891c7512fdcSPavel Labath 
892c7512fdcSPavel Labath     ioVec.iov_base = &regs;
893c7512fdcSPavel Labath     ioVec.iov_len = sizeof regs;
894*b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
895*b9c1b51eSKate Stone                                               &ioVec, sizeof regs);
896c7512fdcSPavel Labath 
897*b9c1b51eSKate Stone     if (error.Success()) {
898*b9c1b51eSKate Stone       ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(),
899*b9c1b51eSKate Stone                16);
900*b9c1b51eSKate Stone       error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset,
901*b9c1b51eSKate Stone                                                 &ioVec, sizeof regs);
902c7512fdcSPavel Labath     }
903*b9c1b51eSKate Stone   } else {
904c7512fdcSPavel Labath     elf_gregset_t regs;
905c7512fdcSPavel Labath     int regset = NT_PRSTATUS;
906c7512fdcSPavel Labath     struct iovec ioVec;
907c7512fdcSPavel Labath 
908c7512fdcSPavel Labath     ioVec.iov_base = &regs;
909c7512fdcSPavel Labath     ioVec.iov_len = sizeof regs;
910*b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
911*b9c1b51eSKate Stone                                               &ioVec, sizeof regs);
912*b9c1b51eSKate Stone     if (error.Success()) {
913*b9c1b51eSKate Stone       ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(),
914*b9c1b51eSKate Stone                8);
915*b9c1b51eSKate Stone       error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset,
916*b9c1b51eSKate Stone                                                 &ioVec, sizeof regs);
917c7512fdcSPavel Labath     }
918c7512fdcSPavel Labath   }
919c7512fdcSPavel Labath   return error;
920068f8a7eSTamas Berghammer }
921068f8a7eSTamas Berghammer 
922*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) {
923c7512fdcSPavel Labath   int regset = NT_PRSTATUS;
924c7512fdcSPavel Labath   struct iovec ioVec;
925c7512fdcSPavel Labath   Error error;
926c7512fdcSPavel Labath 
927c7512fdcSPavel Labath   ioVec.iov_base = buf;
928c7512fdcSPavel Labath   ioVec.iov_len = buf_size;
929*b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
930*b9c1b51eSKate Stone                                            &regset, &ioVec, buf_size);
931068f8a7eSTamas Berghammer }
932068f8a7eSTamas Berghammer 
933*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) {
934c7512fdcSPavel Labath   int regset = NT_PRSTATUS;
935c7512fdcSPavel Labath   struct iovec ioVec;
936c7512fdcSPavel Labath   Error error;
937c7512fdcSPavel Labath 
938c7512fdcSPavel Labath   ioVec.iov_base = buf;
939c7512fdcSPavel Labath   ioVec.iov_len = buf_size;
940*b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
941*b9c1b51eSKate Stone                                            &regset, &ioVec, buf_size);
942068f8a7eSTamas Berghammer }
943068f8a7eSTamas Berghammer 
944*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) {
945c7512fdcSPavel Labath   int regset = NT_FPREGSET;
946c7512fdcSPavel Labath   struct iovec ioVec;
947c7512fdcSPavel Labath   Error error;
948c7512fdcSPavel Labath 
949c7512fdcSPavel Labath   ioVec.iov_base = buf;
950c7512fdcSPavel Labath   ioVec.iov_len = buf_size;
951*b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
952*b9c1b51eSKate Stone                                            &regset, &ioVec, buf_size);
953068f8a7eSTamas Berghammer }
954068f8a7eSTamas Berghammer 
955*b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) {
956c7512fdcSPavel Labath   int regset = NT_FPREGSET;
957c7512fdcSPavel Labath   struct iovec ioVec;
958c7512fdcSPavel Labath   Error error;
959c7512fdcSPavel Labath 
960c7512fdcSPavel Labath   ioVec.iov_base = buf;
961c7512fdcSPavel Labath   ioVec.iov_len = buf_size;
962*b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
963*b9c1b51eSKate Stone                                            &regset, &ioVec, buf_size);
964068f8a7eSTamas Berghammer }
965068f8a7eSTamas Berghammer 
966*b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset(
967*b9c1b51eSKate Stone     const RegisterInfo *reg_info) const {
968*b9c1b51eSKate Stone   return reg_info->byte_offset -
969*b9c1b51eSKate Stone          GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
970c40e7b17STamas Berghammer }
971c40e7b17STamas Berghammer 
972068f8a7eSTamas Berghammer #endif // defined (__arm64__) || defined (__aarch64__)
973