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 
30b9c1b51eSKate Stone // System includes - They have to be included after framework includes because
31b9c1b51eSKate 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.
46b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_arm64[] = {
47b9c1b51eSKate Stone     gpr_x0_arm64,       gpr_x1_arm64,   gpr_x2_arm64,  gpr_x3_arm64,
48b9c1b51eSKate Stone     gpr_x4_arm64,       gpr_x5_arm64,   gpr_x6_arm64,  gpr_x7_arm64,
49b9c1b51eSKate Stone     gpr_x8_arm64,       gpr_x9_arm64,   gpr_x10_arm64, gpr_x11_arm64,
50b9c1b51eSKate Stone     gpr_x12_arm64,      gpr_x13_arm64,  gpr_x14_arm64, gpr_x15_arm64,
51b9c1b51eSKate Stone     gpr_x16_arm64,      gpr_x17_arm64,  gpr_x18_arm64, gpr_x19_arm64,
52b9c1b51eSKate Stone     gpr_x20_arm64,      gpr_x21_arm64,  gpr_x22_arm64, gpr_x23_arm64,
53b9c1b51eSKate Stone     gpr_x24_arm64,      gpr_x25_arm64,  gpr_x26_arm64, gpr_x27_arm64,
54b9c1b51eSKate Stone     gpr_x28_arm64,      gpr_fp_arm64,   gpr_lr_arm64,  gpr_sp_arm64,
55b9c1b51eSKate Stone     gpr_pc_arm64,       gpr_cpsr_arm64,
561e209fccSTamas Berghammer     LLDB_INVALID_REGNUM // register sets need to end with this flag
571e209fccSTamas Berghammer };
58b9c1b51eSKate Stone static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) -
59b9c1b51eSKate 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.
63b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_arm64[] = {
64b9c1b51eSKate Stone     fpu_v0_arm64,       fpu_v1_arm64,   fpu_v2_arm64,  fpu_v3_arm64,
65b9c1b51eSKate Stone     fpu_v4_arm64,       fpu_v5_arm64,   fpu_v6_arm64,  fpu_v7_arm64,
66b9c1b51eSKate Stone     fpu_v8_arm64,       fpu_v9_arm64,   fpu_v10_arm64, fpu_v11_arm64,
67b9c1b51eSKate Stone     fpu_v12_arm64,      fpu_v13_arm64,  fpu_v14_arm64, fpu_v15_arm64,
68b9c1b51eSKate Stone     fpu_v16_arm64,      fpu_v17_arm64,  fpu_v18_arm64, fpu_v19_arm64,
69b9c1b51eSKate Stone     fpu_v20_arm64,      fpu_v21_arm64,  fpu_v22_arm64, fpu_v23_arm64,
70b9c1b51eSKate Stone     fpu_v24_arm64,      fpu_v25_arm64,  fpu_v26_arm64, fpu_v27_arm64,
71b9c1b51eSKate Stone     fpu_v28_arm64,      fpu_v29_arm64,  fpu_v30_arm64, fpu_v31_arm64,
72b9c1b51eSKate Stone     fpu_fpsr_arm64,     fpu_fpcr_arm64,
731e209fccSTamas Berghammer     LLDB_INVALID_REGNUM // register sets need to end with this flag
741e209fccSTamas Berghammer };
75b9c1b51eSKate Stone static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) -
76b9c1b51eSKate 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.
81b9c1b51eSKate Stone enum { k_num_register_sets = 2 };
821e209fccSTamas Berghammer }
831e209fccSTamas Berghammer 
841e209fccSTamas Berghammer // Register sets for ARM64.
85b9c1b51eSKate Stone static const RegisterSet g_reg_sets_arm64[k_num_register_sets] = {
86b9c1b51eSKate Stone     {"General Purpose Registers", "gpr", k_num_gpr_registers_arm64,
87b9c1b51eSKate Stone      g_gpr_regnums_arm64},
88b9c1b51eSKate Stone     {"Floating Point Registers", "fpu", k_num_fpr_registers_arm64,
89b9c1b51eSKate Stone      g_fpu_regnums_arm64}};
901e209fccSTamas Berghammer 
91068f8a7eSTamas Berghammer NativeRegisterContextLinux *
92b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
93b9c1b51eSKate Stone     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
94b9c1b51eSKate Stone     uint32_t concrete_frame_idx) {
95e85e6021STamas Berghammer   Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS);
96b9c1b51eSKate Stone   switch (target_arch.GetMachine()) {
97e85e6021STamas Berghammer   case llvm::Triple::arm:
98b9c1b51eSKate Stone     return new NativeRegisterContextLinux_arm(target_arch, native_thread,
99b9c1b51eSKate Stone                                               concrete_frame_idx);
100e85e6021STamas Berghammer   case llvm::Triple::aarch64:
101b9c1b51eSKate Stone     return new NativeRegisterContextLinux_arm64(target_arch, native_thread,
102b9c1b51eSKate Stone                                                 concrete_frame_idx);
103e85e6021STamas Berghammer   default:
104e85e6021STamas Berghammer     if (log)
105b9c1b51eSKate Stone       log->Printf("NativeRegisterContextLinux::%s() have no register context "
106b9c1b51eSKate Stone                   "for architecture: %s\n",
107b9c1b51eSKate Stone                   __FUNCTION__,
108e85e6021STamas Berghammer                   target_arch.GetTriple().getArchName().str().c_str());
109e85e6021STamas Berghammer     return nullptr;
110e85e6021STamas Berghammer   }
111068f8a7eSTamas Berghammer }
112068f8a7eSTamas Berghammer 
113b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
114b9c1b51eSKate Stone     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
115b9c1b51eSKate Stone     uint32_t concrete_frame_idx)
116b9c1b51eSKate Stone     : NativeRegisterContextLinux(native_thread, concrete_frame_idx,
117b9c1b51eSKate Stone                                  new RegisterContextLinux_arm64(target_arch)) {
118b9c1b51eSKate 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 
145b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::GetRegisterSetCount() const {
1461e209fccSTamas Berghammer   return k_num_register_sets;
1471e209fccSTamas Berghammer }
1481e209fccSTamas Berghammer 
149db264a6dSTamas Berghammer const RegisterSet *
150b9c1b51eSKate 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 
157b9c1b51eSKate 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 
164b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadRegister(
165b9c1b51eSKate Stone     const RegisterInfo *reg_info, RegisterValue &reg_value) {
1661e209fccSTamas Berghammer   Error error;
1671e209fccSTamas Berghammer 
168b9c1b51eSKate 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 
175b9c1b51eSKate Stone   if (IsFPR(reg)) {
176068f8a7eSTamas Berghammer     error = ReadFPR();
177068f8a7eSTamas Berghammer     if (error.Fail())
1781e209fccSTamas Berghammer       return error;
179b9c1b51eSKate Stone   } else {
1801e209fccSTamas Berghammer     uint32_t full_reg = reg;
181b9c1b51eSKate Stone     bool is_subreg = reg_info->invalidate_regs &&
182b9c1b51eSKate Stone                      (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
1831e209fccSTamas Berghammer 
184b9c1b51eSKate 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 
191b9c1b51eSKate Stone     if (error.Success()) {
192b9c1b51eSKate Stone       // If our read was not aligned (for ah,bh,ch,dh), shift our returned value
193b9c1b51eSKate 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 
197b9c1b51eSKate Stone       // If our return byte size was greater than the return value reg size,
198b9c1b51eSKate 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;
210b9c1b51eSKate Stone   reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
211b9c1b51eSKate Stone                               eByteOrderLittle, error);
2121e209fccSTamas Berghammer 
2131e209fccSTamas Berghammer   return error;
2141e209fccSTamas Berghammer }
2151e209fccSTamas Berghammer 
216b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteRegister(
217b9c1b51eSKate 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)
223b9c1b51eSKate Stone     return Error("no lldb regnum for %s", reg_info && reg_info->name
224b9c1b51eSKate Stone                                               ? reg_info->name
225b9c1b51eSKate Stone                                               : "<unknown register>");
2261e209fccSTamas Berghammer 
2271e209fccSTamas Berghammer   if (IsGPR(reg_index))
2281e209fccSTamas Berghammer     return WriteRegisterRaw(reg_index, reg_value);
2291e209fccSTamas Berghammer 
230b9c1b51eSKate 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;
235b9c1b51eSKate 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.");
247b9c1b51eSKate Stone       return Error("unhandled register data size %" PRIu32,
248b9c1b51eSKate 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 
258b9c1b51eSKate Stone   return Error("failed - register wasn't recognized to be a GPR or an FPR, "
259b9c1b51eSKate Stone                "write strategy unknown");
2601e209fccSTamas Berghammer }
2611e209fccSTamas Berghammer 
262b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
263b9c1b51eSKate 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)
268b9c1b51eSKate Stone     return Error("failed to allocate DataBufferHeap instance of size %" PRIu64,
269b9c1b51eSKate 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();
280b9c1b51eSKate Stone   if (dst == nullptr) {
281b9c1b51eSKate Stone     error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
282b9c1b51eSKate Stone                                    " returned a null pointer",
283b9c1b51eSKate 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 
294b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
295b9c1b51eSKate Stone     const lldb::DataBufferSP &data_sp) {
2961e209fccSTamas Berghammer   Error error;
2971e209fccSTamas Berghammer 
298b9c1b51eSKate Stone   if (!data_sp) {
299b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
300b9c1b51eSKate Stone         "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided",
301b9c1b51eSKate Stone         __FUNCTION__);
3021e209fccSTamas Berghammer     return error;
3031e209fccSTamas Berghammer   }
3041e209fccSTamas Berghammer 
305b9c1b51eSKate Stone   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
306b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
307b9c1b51eSKate Stone         "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched "
308b9c1b51eSKate Stone         "data size, expected %" PRIu64 ", actual %" PRIu64,
309b9c1b51eSKate Stone         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
3101e209fccSTamas Berghammer     return error;
3111e209fccSTamas Berghammer   }
3121e209fccSTamas Berghammer 
3131e209fccSTamas Berghammer   uint8_t *src = data_sp->GetBytes();
314b9c1b51eSKate Stone   if (src == nullptr) {
315b9c1b51eSKate Stone     error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s "
316b9c1b51eSKate Stone                                    "DataBuffer::GetBytes() returned a null "
317b9c1b51eSKate Stone                                    "pointer",
318b9c1b51eSKate 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 
337b9c1b51eSKate 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 
341b9c1b51eSKate 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
346b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::SetHardwareBreakpoint(lldb::addr_t addr,
347b9c1b51eSKate 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)
365b9c1b51eSKate Stone     return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware
366b9c1b51eSKate 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;
380b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
381b9c1b51eSKate Stone     if ((m_hbr_regs[i].control & 1) == 0) {
382ea8c25a8SOmair Javaid       bp_index = i; // Mark last free slot
383b9c1b51eSKate Stone     } else if (m_hbr_regs[i].address == addr &&
384b9c1b51eSKate 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
394b9c1b51eSKate 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 
402b9c1b51eSKate 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     }
409b9c1b51eSKate Stone   } else
410ea8c25a8SOmair Javaid     m_hbr_regs[bp_index].refcount++;
411ea8c25a8SOmair Javaid 
412ea8c25a8SOmair Javaid   return bp_index;
413ea8c25a8SOmair Javaid }
414ea8c25a8SOmair Javaid 
415b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint(
416b9c1b51eSKate 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.
434b9c1b51eSKate Stone   if (m_hbr_regs[hw_idx].refcount > 1) {
435ea8c25a8SOmair Javaid     m_hbr_regs[hw_idx].refcount--;
436ea8c25a8SOmair Javaid     return true;
437b9c1b51eSKate 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 
450b9c1b51eSKate 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 
464b9c1b51eSKate 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 
481b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::SetHardwareWatchpoint(
482b9c1b51eSKate 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.
501b9c1b51eSKate 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.
521b9c1b51eSKate 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 
541*05ac4c44SOmair Javaid   // Iterate over stored watchpoints and find a free wp_index
542ea8c25a8SOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
543b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
544b9c1b51eSKate Stone     if ((m_hwp_regs[i].control & 1) == 0) {
545ea8c25a8SOmair Javaid       wp_index = i; // Mark last free slot
546*05ac4c44SOmair Javaid     } else if (m_hwp_regs[i].address == addr) {
547*05ac4c44SOmair Javaid       return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
548ea8c25a8SOmair Javaid     }
549ea8c25a8SOmair Javaid   }
550ea8c25a8SOmair Javaid 
551ea8c25a8SOmair Javaid   if (wp_index == LLDB_INVALID_INDEX32)
552ea8c25a8SOmair Javaid     return LLDB_INVALID_INDEX32;
553ea8c25a8SOmair Javaid 
5541fd2a8cfSOmair Javaid   // Update watchpoint in local cache
55543507f57SOmair Javaid   m_hwp_regs[wp_index].real_addr = real_addr;
556ea8c25a8SOmair Javaid   m_hwp_regs[wp_index].address = addr;
557ea8c25a8SOmair Javaid   m_hwp_regs[wp_index].control = control_value;
558ea8c25a8SOmair Javaid 
559ea8c25a8SOmair Javaid   // PTRACE call to set corresponding watchpoint register.
5603a56363aSOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeWATCH);
5613a56363aSOmair Javaid 
562b9c1b51eSKate Stone   if (error.Fail()) {
563f24741d9SOmair Javaid     m_hwp_regs[wp_index].address = 0;
564f24741d9SOmair Javaid     m_hwp_regs[wp_index].control &= ~1;
565f24741d9SOmair Javaid 
5663a56363aSOmair Javaid     return LLDB_INVALID_INDEX32;
567ea8c25a8SOmair Javaid   }
568ea8c25a8SOmair Javaid 
569ea8c25a8SOmair Javaid   return wp_index;
570ea8c25a8SOmair Javaid }
571ea8c25a8SOmair Javaid 
572b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint(
573b9c1b51eSKate Stone     uint32_t wp_index) {
574ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
575ea8c25a8SOmair Javaid 
576ea8c25a8SOmair Javaid   if (log)
577ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
578ea8c25a8SOmair Javaid 
5793a56363aSOmair Javaid   Error error;
5803a56363aSOmair Javaid 
5811fd2a8cfSOmair Javaid   // Read hardware breakpoint and watchpoint information.
5823a56363aSOmair Javaid   error = ReadHardwareDebugInfo();
5833a56363aSOmair Javaid 
5843a56363aSOmair Javaid   if (error.Fail())
5853a56363aSOmair Javaid     return false;
586ea8c25a8SOmair Javaid 
587ea8c25a8SOmair Javaid   if (wp_index >= m_max_hwp_supported)
588ea8c25a8SOmair Javaid     return false;
589ea8c25a8SOmair Javaid 
590f24741d9SOmair Javaid   // Create a backup we can revert to in case of failure.
591f24741d9SOmair Javaid   lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
592f24741d9SOmair Javaid   uint32_t tempControl = m_hwp_regs[wp_index].control;
593f24741d9SOmair Javaid 
5941fd2a8cfSOmair Javaid   // Update watchpoint in local cache
595ea8c25a8SOmair Javaid   m_hwp_regs[wp_index].control &= ~1;
596ea8c25a8SOmair Javaid   m_hwp_regs[wp_index].address = 0;
597ea8c25a8SOmair Javaid 
5981fd2a8cfSOmair Javaid   // Ptrace call to update hardware debug registers
5993a56363aSOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeWATCH);
6003a56363aSOmair Javaid 
601b9c1b51eSKate Stone   if (error.Fail()) {
602f24741d9SOmair Javaid     m_hwp_regs[wp_index].control = tempControl;
603f24741d9SOmair Javaid     m_hwp_regs[wp_index].address = tempAddr;
604f24741d9SOmair Javaid 
6053a56363aSOmair Javaid     return false;
606f24741d9SOmair Javaid   }
6073a56363aSOmair Javaid 
608ea8c25a8SOmair Javaid   return true;
609ea8c25a8SOmair Javaid }
610ea8c25a8SOmair Javaid 
611b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints() {
612ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
613ea8c25a8SOmair Javaid 
614ea8c25a8SOmair Javaid   if (log)
615ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
616ea8c25a8SOmair Javaid 
6173a56363aSOmair Javaid   Error error;
6183a56363aSOmair Javaid 
6191fd2a8cfSOmair Javaid   // Read hardware breakpoint and watchpoint information.
6203a56363aSOmair Javaid   error = ReadHardwareDebugInfo();
6213a56363aSOmair Javaid 
6223a56363aSOmair Javaid   if (error.Fail())
6233a56363aSOmair Javaid     return error;
624ea8c25a8SOmair Javaid 
625f24741d9SOmair Javaid   lldb::addr_t tempAddr = 0;
626f24741d9SOmair Javaid   uint32_t tempControl = 0, tempRefCount = 0;
627f24741d9SOmair Javaid 
628b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
629b9c1b51eSKate Stone     if (m_hwp_regs[i].control & 0x01) {
630f24741d9SOmair Javaid       // Create a backup we can revert to in case of failure.
631f24741d9SOmair Javaid       tempAddr = m_hwp_regs[i].address;
632f24741d9SOmair Javaid       tempControl = m_hwp_regs[i].control;
633f24741d9SOmair Javaid 
6341fd2a8cfSOmair Javaid       // Clear watchpoints in local cache
635ea8c25a8SOmair Javaid       m_hwp_regs[i].control &= ~1;
636ea8c25a8SOmair Javaid       m_hwp_regs[i].address = 0;
637ea8c25a8SOmair Javaid 
6381fd2a8cfSOmair Javaid       // Ptrace call to update hardware debug registers
6393a56363aSOmair Javaid       error = WriteHardwareDebugRegs(eDREGTypeWATCH);
6403a56363aSOmair Javaid 
641b9c1b51eSKate Stone       if (error.Fail()) {
642f24741d9SOmair Javaid         m_hwp_regs[i].control = tempControl;
643f24741d9SOmair Javaid         m_hwp_regs[i].address = tempAddr;
644f24741d9SOmair Javaid 
6453a56363aSOmair Javaid         return error;
646ea8c25a8SOmair Javaid       }
647ea8c25a8SOmair Javaid     }
648f24741d9SOmair Javaid   }
649ea8c25a8SOmair Javaid 
650ea8c25a8SOmair Javaid   return Error();
651ea8c25a8SOmair Javaid }
652ea8c25a8SOmair Javaid 
653ea8c25a8SOmair Javaid uint32_t
654b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) {
655ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
656ea8c25a8SOmair Javaid 
657ea8c25a8SOmair Javaid   if (log)
658ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
659b9c1b51eSKate Stone   switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) {
660ea8c25a8SOmair Javaid   case 0x01:
661ea8c25a8SOmair Javaid     return 1;
662ea8c25a8SOmair Javaid   case 0x03:
663ea8c25a8SOmair Javaid     return 2;
664ea8c25a8SOmair Javaid   case 0x0f:
665ea8c25a8SOmair Javaid     return 4;
666ea8c25a8SOmair Javaid   case 0xff:
667ea8c25a8SOmair Javaid     return 8;
668ea8c25a8SOmair Javaid   default:
669ea8c25a8SOmair Javaid     return 0;
670ea8c25a8SOmair Javaid   }
671ea8c25a8SOmair Javaid }
672b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) {
673ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
674ea8c25a8SOmair Javaid 
675ea8c25a8SOmair Javaid   if (log)
676ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
677ea8c25a8SOmair Javaid 
678ea8c25a8SOmair Javaid   if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
679ea8c25a8SOmair Javaid     return true;
680ea8c25a8SOmair Javaid   else
681ea8c25a8SOmair Javaid     return false;
682ea8c25a8SOmair Javaid }
683ea8c25a8SOmair Javaid 
684b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(
685b9c1b51eSKate Stone     uint32_t &wp_index, lldb::addr_t trap_addr) {
686ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
687ea8c25a8SOmair Javaid 
688ea8c25a8SOmair Javaid   if (log)
689ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
690ea8c25a8SOmair Javaid 
691ea8c25a8SOmair Javaid   uint32_t watch_size;
692ea8c25a8SOmair Javaid   lldb::addr_t watch_addr;
693ea8c25a8SOmair Javaid 
694b9c1b51eSKate Stone   for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
695ea8c25a8SOmair Javaid     watch_size = GetWatchpointSize(wp_index);
696ea8c25a8SOmair Javaid     watch_addr = m_hwp_regs[wp_index].address;
697ea8c25a8SOmair Javaid 
698*05ac4c44SOmair Javaid     if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
699*05ac4c44SOmair Javaid         trap_addr < watch_addr + watch_size) {
70043507f57SOmair Javaid       m_hwp_regs[wp_index].hit_addr = trap_addr;
701ea8c25a8SOmair Javaid       return Error();
702ea8c25a8SOmair Javaid     }
703ea8c25a8SOmair Javaid   }
704ea8c25a8SOmair Javaid 
705ea8c25a8SOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
706ea8c25a8SOmair Javaid   return Error();
707ea8c25a8SOmair Javaid }
708ea8c25a8SOmair Javaid 
709ea8c25a8SOmair Javaid lldb::addr_t
710b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointAddress(uint32_t wp_index) {
711ea8c25a8SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
712ea8c25a8SOmair Javaid 
713ea8c25a8SOmair Javaid   if (log)
714ea8c25a8SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
715ea8c25a8SOmair Javaid 
716ea8c25a8SOmair Javaid   if (wp_index >= m_max_hwp_supported)
717ea8c25a8SOmair Javaid     return LLDB_INVALID_ADDRESS;
718ea8c25a8SOmair Javaid 
719ea8c25a8SOmair Javaid   if (WatchpointIsEnabled(wp_index))
72043507f57SOmair Javaid     return m_hwp_regs[wp_index].real_addr;
72143507f57SOmair Javaid   else
72243507f57SOmair Javaid     return LLDB_INVALID_ADDRESS;
72343507f57SOmair Javaid }
72443507f57SOmair Javaid 
72543507f57SOmair Javaid lldb::addr_t
726b9c1b51eSKate Stone NativeRegisterContextLinux_arm64::GetWatchpointHitAddress(uint32_t wp_index) {
72743507f57SOmair Javaid   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
72843507f57SOmair Javaid 
72943507f57SOmair Javaid   if (log)
73043507f57SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
73143507f57SOmair Javaid 
73243507f57SOmair Javaid   if (wp_index >= m_max_hwp_supported)
73343507f57SOmair Javaid     return LLDB_INVALID_ADDRESS;
73443507f57SOmair Javaid 
73543507f57SOmair Javaid   if (WatchpointIsEnabled(wp_index))
73643507f57SOmair Javaid     return m_hwp_regs[wp_index].hit_addr;
737ea8c25a8SOmair Javaid   else
738ea8c25a8SOmair Javaid     return LLDB_INVALID_ADDRESS;
739ea8c25a8SOmair Javaid }
740ea8c25a8SOmair Javaid 
741b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
742b9c1b51eSKate Stone   if (!m_refresh_hwdebug_info) {
7431fd2a8cfSOmair Javaid     return Error();
7441fd2a8cfSOmair Javaid   }
7451fd2a8cfSOmair Javaid 
746c7512fdcSPavel Labath   ::pid_t tid = m_thread.GetID();
747ea8c25a8SOmair Javaid 
748c7512fdcSPavel Labath   int regset = NT_ARM_HW_WATCH;
749c7512fdcSPavel Labath   struct iovec ioVec;
750c7512fdcSPavel Labath   struct user_hwdebug_state dreg_state;
751c7512fdcSPavel Labath   Error error;
752c7512fdcSPavel Labath 
753c7512fdcSPavel Labath   ioVec.iov_base = &dreg_state;
754c7512fdcSPavel Labath   ioVec.iov_len = sizeof(dreg_state);
755b9c1b51eSKate Stone   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
756b9c1b51eSKate Stone                                             &ioVec, ioVec.iov_len);
7573a56363aSOmair Javaid 
7583a56363aSOmair Javaid   if (error.Fail())
7593a56363aSOmair Javaid     return error;
7603a56363aSOmair Javaid 
7611fd2a8cfSOmair Javaid   m_max_hwp_supported = dreg_state.dbg_info & 0xff;
762c7512fdcSPavel Labath 
763c7512fdcSPavel Labath   regset = NT_ARM_HW_BREAK;
764b9c1b51eSKate Stone   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
765b9c1b51eSKate Stone                                             &ioVec, ioVec.iov_len);
7661fd2a8cfSOmair Javaid 
7673a56363aSOmair Javaid   if (error.Fail())
7683a56363aSOmair Javaid     return error;
7693a56363aSOmair Javaid 
7703a56363aSOmair Javaid   m_max_hbp_supported = dreg_state.dbg_info & 0xff;
7711fd2a8cfSOmair Javaid   m_refresh_hwdebug_info = false;
772c7512fdcSPavel Labath 
773c7512fdcSPavel Labath   return error;
774ea8c25a8SOmair Javaid }
775068f8a7eSTamas Berghammer 
776b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) {
777c7512fdcSPavel Labath   struct iovec ioVec;
778c7512fdcSPavel Labath   struct user_hwdebug_state dreg_state;
779c7512fdcSPavel Labath   Error error;
780c7512fdcSPavel Labath 
781c7512fdcSPavel Labath   memset(&dreg_state, 0, sizeof(dreg_state));
782c7512fdcSPavel Labath   ioVec.iov_base = &dreg_state;
783c7512fdcSPavel Labath 
784b9c1b51eSKate Stone   if (hwbType == eDREGTypeWATCH) {
7851fd2a8cfSOmair Javaid     hwbType = NT_ARM_HW_WATCH;
786b9c1b51eSKate Stone     ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
787b9c1b51eSKate Stone                     (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
7881fd2a8cfSOmair Javaid 
789b9c1b51eSKate Stone     for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
7901fd2a8cfSOmair Javaid       dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
7911fd2a8cfSOmair Javaid       dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
7921fd2a8cfSOmair Javaid     }
793b9c1b51eSKate Stone   } else {
7941fd2a8cfSOmair Javaid     hwbType = NT_ARM_HW_BREAK;
795b9c1b51eSKate Stone     ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
796b9c1b51eSKate Stone                     (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
7971fd2a8cfSOmair Javaid 
798b9c1b51eSKate Stone     for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
7991fd2a8cfSOmair Javaid       dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address;
8001fd2a8cfSOmair Javaid       dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control;
8011fd2a8cfSOmair Javaid     }
802068f8a7eSTamas Berghammer   }
803068f8a7eSTamas Berghammer 
804b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
805b9c1b51eSKate Stone                                            &hwbType, &ioVec, ioVec.iov_len);
806c7512fdcSPavel Labath }
807c7512fdcSPavel Labath 
808b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadRegisterValue(
809b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, uint32_t size,
810b9c1b51eSKate Stone     RegisterValue &value) {
811c7512fdcSPavel Labath   Error error;
812b9c1b51eSKate Stone   if (offset > sizeof(struct user_pt_regs)) {
813c7512fdcSPavel Labath     uintptr_t offset = offset - sizeof(struct user_pt_regs);
814b9c1b51eSKate Stone     if (offset > sizeof(struct user_fpsimd_state)) {
815c7512fdcSPavel Labath       error.SetErrorString("invalid offset value");
816c7512fdcSPavel Labath       return error;
817c7512fdcSPavel Labath     }
818c7512fdcSPavel Labath     elf_fpregset_t regs;
819c7512fdcSPavel Labath     int regset = NT_FPREGSET;
820c7512fdcSPavel Labath     struct iovec ioVec;
821c7512fdcSPavel Labath 
822c7512fdcSPavel Labath     ioVec.iov_base = &regs;
823c7512fdcSPavel Labath     ioVec.iov_len = sizeof regs;
8244a9babb2SPavel Labath     error = NativeProcessLinux::PtraceWrapper(
8254a9babb2SPavel Labath         PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
826b9c1b51eSKate Stone     if (error.Success()) {
827c7512fdcSPavel Labath       ArchSpec arch;
828c7512fdcSPavel Labath       if (m_thread.GetProcess()->GetArchitecture(arch))
829b9c1b51eSKate Stone         value.SetBytes((void *)(((unsigned char *)(&regs)) + offset), 16,
830b9c1b51eSKate Stone                        arch.GetByteOrder());
831c7512fdcSPavel Labath       else
832c7512fdcSPavel Labath         error.SetErrorString("failed to get architecture");
833c7512fdcSPavel Labath     }
834b9c1b51eSKate Stone   } else {
835c7512fdcSPavel Labath     elf_gregset_t regs;
836c7512fdcSPavel Labath     int regset = NT_PRSTATUS;
837c7512fdcSPavel Labath     struct iovec ioVec;
838c7512fdcSPavel Labath 
839c7512fdcSPavel Labath     ioVec.iov_base = &regs;
840c7512fdcSPavel Labath     ioVec.iov_len = sizeof regs;
8414a9babb2SPavel Labath     error = NativeProcessLinux::PtraceWrapper(
8424a9babb2SPavel Labath         PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
843b9c1b51eSKate Stone     if (error.Success()) {
844c7512fdcSPavel Labath       ArchSpec arch;
845c7512fdcSPavel Labath       if (m_thread.GetProcess()->GetArchitecture(arch))
846b9c1b51eSKate Stone         value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8,
847b9c1b51eSKate Stone                        arch.GetByteOrder());
848c7512fdcSPavel Labath       else
849c7512fdcSPavel Labath         error.SetErrorString("failed to get architecture");
850c7512fdcSPavel Labath     }
851c7512fdcSPavel Labath   }
852c7512fdcSPavel Labath   return error;
853068f8a7eSTamas Berghammer }
854068f8a7eSTamas Berghammer 
855b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteRegisterValue(
856b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, const RegisterValue &value) {
857c7512fdcSPavel Labath   Error error;
858c7512fdcSPavel Labath   ::pid_t tid = m_thread.GetID();
859b9c1b51eSKate Stone   if (offset > sizeof(struct user_pt_regs)) {
860c7512fdcSPavel Labath     uintptr_t offset = offset - sizeof(struct user_pt_regs);
861b9c1b51eSKate Stone     if (offset > sizeof(struct user_fpsimd_state)) {
862c7512fdcSPavel Labath       error.SetErrorString("invalid offset value");
863c7512fdcSPavel Labath       return error;
864c7512fdcSPavel Labath     }
865c7512fdcSPavel Labath     elf_fpregset_t regs;
866c7512fdcSPavel Labath     int regset = NT_FPREGSET;
867c7512fdcSPavel Labath     struct iovec ioVec;
868c7512fdcSPavel Labath 
869c7512fdcSPavel Labath     ioVec.iov_base = &regs;
870c7512fdcSPavel Labath     ioVec.iov_len = sizeof regs;
871b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
872b9c1b51eSKate Stone                                               &ioVec, sizeof regs);
873c7512fdcSPavel Labath 
874b9c1b51eSKate Stone     if (error.Success()) {
875b9c1b51eSKate Stone       ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(),
876b9c1b51eSKate Stone                16);
877b9c1b51eSKate Stone       error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset,
878b9c1b51eSKate Stone                                                 &ioVec, sizeof regs);
879c7512fdcSPavel Labath     }
880b9c1b51eSKate Stone   } else {
881c7512fdcSPavel Labath     elf_gregset_t regs;
882c7512fdcSPavel Labath     int regset = NT_PRSTATUS;
883c7512fdcSPavel Labath     struct iovec ioVec;
884c7512fdcSPavel Labath 
885c7512fdcSPavel Labath     ioVec.iov_base = &regs;
886c7512fdcSPavel Labath     ioVec.iov_len = sizeof regs;
887b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
888b9c1b51eSKate Stone                                               &ioVec, sizeof regs);
889b9c1b51eSKate Stone     if (error.Success()) {
890b9c1b51eSKate Stone       ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(),
891b9c1b51eSKate Stone                8);
892b9c1b51eSKate Stone       error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset,
893b9c1b51eSKate Stone                                                 &ioVec, sizeof regs);
894c7512fdcSPavel Labath     }
895c7512fdcSPavel Labath   }
896c7512fdcSPavel Labath   return error;
897068f8a7eSTamas Berghammer }
898068f8a7eSTamas Berghammer 
899b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) {
900c7512fdcSPavel Labath   int regset = NT_PRSTATUS;
901c7512fdcSPavel Labath   struct iovec ioVec;
902c7512fdcSPavel Labath   Error error;
903c7512fdcSPavel Labath 
904c7512fdcSPavel Labath   ioVec.iov_base = buf;
905c7512fdcSPavel Labath   ioVec.iov_len = buf_size;
906b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
907b9c1b51eSKate Stone                                            &regset, &ioVec, buf_size);
908068f8a7eSTamas Berghammer }
909068f8a7eSTamas Berghammer 
910b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) {
911c7512fdcSPavel Labath   int regset = NT_PRSTATUS;
912c7512fdcSPavel Labath   struct iovec ioVec;
913c7512fdcSPavel Labath   Error error;
914c7512fdcSPavel Labath 
915c7512fdcSPavel Labath   ioVec.iov_base = buf;
916c7512fdcSPavel Labath   ioVec.iov_len = buf_size;
917b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
918b9c1b51eSKate Stone                                            &regset, &ioVec, buf_size);
919068f8a7eSTamas Berghammer }
920068f8a7eSTamas Berghammer 
921b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) {
922c7512fdcSPavel Labath   int regset = NT_FPREGSET;
923c7512fdcSPavel Labath   struct iovec ioVec;
924c7512fdcSPavel Labath   Error error;
925c7512fdcSPavel Labath 
926c7512fdcSPavel Labath   ioVec.iov_base = buf;
927c7512fdcSPavel Labath   ioVec.iov_len = buf_size;
928b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
929b9c1b51eSKate Stone                                            &regset, &ioVec, buf_size);
930068f8a7eSTamas Berghammer }
931068f8a7eSTamas Berghammer 
932b9c1b51eSKate Stone Error NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) {
933c7512fdcSPavel Labath   int regset = NT_FPREGSET;
934c7512fdcSPavel Labath   struct iovec ioVec;
935c7512fdcSPavel Labath   Error error;
936c7512fdcSPavel Labath 
937c7512fdcSPavel Labath   ioVec.iov_base = buf;
938c7512fdcSPavel Labath   ioVec.iov_len = buf_size;
939b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
940b9c1b51eSKate Stone                                            &regset, &ioVec, buf_size);
941068f8a7eSTamas Berghammer }
942068f8a7eSTamas Berghammer 
943b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset(
944b9c1b51eSKate Stone     const RegisterInfo *reg_info) const {
945b9c1b51eSKate Stone   return reg_info->byte_offset -
946b9c1b51eSKate Stone          GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
947c40e7b17STamas Berghammer }
948c40e7b17STamas Berghammer 
949068f8a7eSTamas Berghammer #endif // defined (__arm64__) || defined (__aarch64__)
950