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 
121e209fccSTamas Berghammer #include "NativeRegisterContextLinux_arm64.h"
131e209fccSTamas Berghammer 
14068f8a7eSTamas Berghammer // C Includes
15068f8a7eSTamas Berghammer // C++ Includes
16068f8a7eSTamas Berghammer 
17068f8a7eSTamas Berghammer // Other libraries and framework includes
181e209fccSTamas Berghammer #include "lldb/Core/DataBufferHeap.h"
191e209fccSTamas Berghammer #include "lldb/Core/Error.h"
20068f8a7eSTamas Berghammer #include "lldb/Core/Log.h"
211e209fccSTamas Berghammer #include "lldb/Core/RegisterValue.h"
221e209fccSTamas Berghammer #include "lldb/Host/common/NativeProcessProtocol.h"
231e209fccSTamas Berghammer 
24068f8a7eSTamas Berghammer #include "Plugins/Process/Linux/NativeProcessLinux.h"
25068f8a7eSTamas Berghammer #include "Plugins/Process/Linux/Procfs.h"
26068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
27068f8a7eSTamas Berghammer 
28068f8a7eSTamas Berghammer // System includes - They have to be included after framework includes because they define some
29068f8a7eSTamas Berghammer // macros which collide with variable names in other modules
30068f8a7eSTamas Berghammer #include <sys/socket.h>
31068f8a7eSTamas Berghammer // NT_PRSTATUS and NT_FPREGSET definition
32068f8a7eSTamas Berghammer #include <elf.h>
33068f8a7eSTamas Berghammer 
34068f8a7eSTamas Berghammer #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
351e209fccSTamas Berghammer 
361e209fccSTamas Berghammer using namespace lldb;
371e209fccSTamas Berghammer using namespace lldb_private;
38db264a6dSTamas Berghammer using namespace lldb_private::process_linux;
391e209fccSTamas Berghammer 
401e209fccSTamas Berghammer // ARM64 general purpose registers.
411e209fccSTamas Berghammer static const uint32_t g_gpr_regnums_arm64[] =
421e209fccSTamas Berghammer {
431e209fccSTamas Berghammer     gpr_x0_arm64,
441e209fccSTamas Berghammer     gpr_x1_arm64,
451e209fccSTamas Berghammer     gpr_x2_arm64,
461e209fccSTamas Berghammer     gpr_x3_arm64,
471e209fccSTamas Berghammer     gpr_x4_arm64,
481e209fccSTamas Berghammer     gpr_x5_arm64,
491e209fccSTamas Berghammer     gpr_x6_arm64,
501e209fccSTamas Berghammer     gpr_x7_arm64,
511e209fccSTamas Berghammer     gpr_x8_arm64,
521e209fccSTamas Berghammer     gpr_x9_arm64,
531e209fccSTamas Berghammer     gpr_x10_arm64,
541e209fccSTamas Berghammer     gpr_x11_arm64,
551e209fccSTamas Berghammer     gpr_x12_arm64,
561e209fccSTamas Berghammer     gpr_x13_arm64,
571e209fccSTamas Berghammer     gpr_x14_arm64,
581e209fccSTamas Berghammer     gpr_x15_arm64,
591e209fccSTamas Berghammer     gpr_x16_arm64,
601e209fccSTamas Berghammer     gpr_x17_arm64,
611e209fccSTamas Berghammer     gpr_x18_arm64,
621e209fccSTamas Berghammer     gpr_x19_arm64,
631e209fccSTamas Berghammer     gpr_x20_arm64,
641e209fccSTamas Berghammer     gpr_x21_arm64,
651e209fccSTamas Berghammer     gpr_x22_arm64,
661e209fccSTamas Berghammer     gpr_x23_arm64,
671e209fccSTamas Berghammer     gpr_x24_arm64,
681e209fccSTamas Berghammer     gpr_x25_arm64,
691e209fccSTamas Berghammer     gpr_x26_arm64,
701e209fccSTamas Berghammer     gpr_x27_arm64,
711e209fccSTamas Berghammer     gpr_x28_arm64,
721e209fccSTamas Berghammer     gpr_fp_arm64,
731e209fccSTamas Berghammer     gpr_lr_arm64,
741e209fccSTamas Berghammer     gpr_sp_arm64,
751e209fccSTamas Berghammer     gpr_pc_arm64,
761e209fccSTamas Berghammer     gpr_cpsr_arm64,
771e209fccSTamas Berghammer     LLDB_INVALID_REGNUM // register sets need to end with this flag
781e209fccSTamas Berghammer };
791e209fccSTamas Berghammer static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \
801e209fccSTamas Berghammer               "g_gpr_regnums_arm64 has wrong number of register infos");
811e209fccSTamas Berghammer 
821e209fccSTamas Berghammer // ARM64 floating point registers.
831e209fccSTamas Berghammer static const uint32_t g_fpu_regnums_arm64[] =
841e209fccSTamas Berghammer {
851e209fccSTamas Berghammer     fpu_v0_arm64,
861e209fccSTamas Berghammer     fpu_v1_arm64,
871e209fccSTamas Berghammer     fpu_v2_arm64,
881e209fccSTamas Berghammer     fpu_v3_arm64,
891e209fccSTamas Berghammer     fpu_v4_arm64,
901e209fccSTamas Berghammer     fpu_v5_arm64,
911e209fccSTamas Berghammer     fpu_v6_arm64,
921e209fccSTamas Berghammer     fpu_v7_arm64,
931e209fccSTamas Berghammer     fpu_v8_arm64,
941e209fccSTamas Berghammer     fpu_v9_arm64,
951e209fccSTamas Berghammer     fpu_v10_arm64,
961e209fccSTamas Berghammer     fpu_v11_arm64,
971e209fccSTamas Berghammer     fpu_v12_arm64,
981e209fccSTamas Berghammer     fpu_v13_arm64,
991e209fccSTamas Berghammer     fpu_v14_arm64,
1001e209fccSTamas Berghammer     fpu_v15_arm64,
1011e209fccSTamas Berghammer     fpu_v16_arm64,
1021e209fccSTamas Berghammer     fpu_v17_arm64,
1031e209fccSTamas Berghammer     fpu_v18_arm64,
1041e209fccSTamas Berghammer     fpu_v19_arm64,
1051e209fccSTamas Berghammer     fpu_v20_arm64,
1061e209fccSTamas Berghammer     fpu_v21_arm64,
1071e209fccSTamas Berghammer     fpu_v22_arm64,
1081e209fccSTamas Berghammer     fpu_v23_arm64,
1091e209fccSTamas Berghammer     fpu_v24_arm64,
1101e209fccSTamas Berghammer     fpu_v25_arm64,
1111e209fccSTamas Berghammer     fpu_v26_arm64,
1121e209fccSTamas Berghammer     fpu_v27_arm64,
1131e209fccSTamas Berghammer     fpu_v28_arm64,
1141e209fccSTamas Berghammer     fpu_v29_arm64,
1151e209fccSTamas Berghammer     fpu_v30_arm64,
1161e209fccSTamas Berghammer     fpu_v31_arm64,
1171e209fccSTamas Berghammer     fpu_fpsr_arm64,
1181e209fccSTamas Berghammer     fpu_fpcr_arm64,
1191e209fccSTamas Berghammer     LLDB_INVALID_REGNUM // register sets need to end with this flag
1201e209fccSTamas Berghammer };
1211e209fccSTamas Berghammer static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \
1221e209fccSTamas Berghammer               "g_fpu_regnums_arm64 has wrong number of register infos");
1231e209fccSTamas Berghammer 
1241e209fccSTamas Berghammer namespace {
1251e209fccSTamas Berghammer     // Number of register sets provided by this context.
1261e209fccSTamas Berghammer     enum
1271e209fccSTamas Berghammer     {
1281e209fccSTamas Berghammer         k_num_register_sets = 2
1291e209fccSTamas Berghammer     };
1301e209fccSTamas Berghammer }
1311e209fccSTamas Berghammer 
1321e209fccSTamas Berghammer // Register sets for ARM64.
133db264a6dSTamas Berghammer static const RegisterSet
1341e209fccSTamas Berghammer g_reg_sets_arm64[k_num_register_sets] =
1351e209fccSTamas Berghammer {
1361e209fccSTamas Berghammer     { "General Purpose Registers",  "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 },
1371e209fccSTamas Berghammer     { "Floating Point Registers",   "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 }
1381e209fccSTamas Berghammer };
1391e209fccSTamas Berghammer 
140068f8a7eSTamas Berghammer NativeRegisterContextLinux*
141068f8a7eSTamas Berghammer NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
142068f8a7eSTamas Berghammer                                                                  NativeThreadProtocol &native_thread,
143068f8a7eSTamas Berghammer                                                                  uint32_t concrete_frame_idx)
144068f8a7eSTamas Berghammer {
145068f8a7eSTamas Berghammer     return new NativeRegisterContextLinux_arm64(target_arch, native_thread, concrete_frame_idx);
146068f8a7eSTamas Berghammer }
147068f8a7eSTamas Berghammer 
148068f8a7eSTamas Berghammer NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (const ArchSpec& target_arch,
149068f8a7eSTamas Berghammer                                                                     NativeThreadProtocol &native_thread,
150068f8a7eSTamas Berghammer                                                                     uint32_t concrete_frame_idx) :
151068f8a7eSTamas Berghammer     NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm64(target_arch))
152068f8a7eSTamas Berghammer {
153068f8a7eSTamas Berghammer     switch (target_arch.GetMachine())
1541e209fccSTamas Berghammer     {
1551e209fccSTamas Berghammer         case llvm::Triple::aarch64:
1561e209fccSTamas Berghammer             m_reg_info.num_registers     = k_num_registers_arm64;
1571e209fccSTamas Berghammer             m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64;
1581e209fccSTamas Berghammer             m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64;
1591e209fccSTamas Berghammer             m_reg_info.last_gpr          = k_last_gpr_arm64;
1601e209fccSTamas Berghammer             m_reg_info.first_fpr         = k_first_fpr_arm64;
1611e209fccSTamas Berghammer             m_reg_info.last_fpr          = k_last_fpr_arm64;
1621e209fccSTamas Berghammer             m_reg_info.first_fpr_v       = fpu_v0_arm64;
1631e209fccSTamas Berghammer             m_reg_info.last_fpr_v        = fpu_v31_arm64;
1641e209fccSTamas Berghammer             m_reg_info.gpr_flags         = gpr_cpsr_arm64;
1651e209fccSTamas Berghammer             break;
1661e209fccSTamas Berghammer         default:
1671e209fccSTamas Berghammer             assert(false && "Unhandled target architecture.");
1681e209fccSTamas Berghammer             break;
1691e209fccSTamas Berghammer     }
1701e209fccSTamas Berghammer 
1711e209fccSTamas Berghammer     ::memset(&m_fpr, 0, sizeof (m_fpr));
1721e209fccSTamas Berghammer     ::memset(&m_gpr_arm64, 0, sizeof (m_gpr_arm64));
173ea8c25a8SOmair Javaid     ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs));
174ea8c25a8SOmair Javaid 
175ea8c25a8SOmair Javaid     // 16 is just a maximum value, query hardware for actual watchpoint count
176ea8c25a8SOmair Javaid     m_max_hwp_supported = 16;
177ea8c25a8SOmair Javaid     m_max_hbp_supported = 16;
178ea8c25a8SOmair Javaid     m_refresh_hwdebug_info = true;
1791e209fccSTamas Berghammer }
1801e209fccSTamas Berghammer 
1811e209fccSTamas Berghammer uint32_t
1821e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetRegisterSetCount () const
1831e209fccSTamas Berghammer {
1841e209fccSTamas Berghammer     return k_num_register_sets;
1851e209fccSTamas Berghammer }
1861e209fccSTamas Berghammer 
187db264a6dSTamas Berghammer const RegisterSet *
1881e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetRegisterSet (uint32_t set_index) const
1891e209fccSTamas Berghammer {
1901e209fccSTamas Berghammer     if (set_index < k_num_register_sets)
1911e209fccSTamas Berghammer         return &g_reg_sets_arm64[set_index];
1921e209fccSTamas Berghammer 
1931e209fccSTamas Berghammer     return nullptr;
1941e209fccSTamas Berghammer }
1951e209fccSTamas Berghammer 
196db264a6dSTamas Berghammer Error
1971e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
1981e209fccSTamas Berghammer {
1991e209fccSTamas Berghammer     Error error;
2001e209fccSTamas Berghammer 
2011e209fccSTamas Berghammer     if (!reg_info)
2021e209fccSTamas Berghammer     {
2031e209fccSTamas Berghammer         error.SetErrorString ("reg_info NULL");
2041e209fccSTamas Berghammer         return error;
2051e209fccSTamas Berghammer     }
2061e209fccSTamas Berghammer 
2071e209fccSTamas Berghammer     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
2081e209fccSTamas Berghammer 
2091e209fccSTamas Berghammer     if (IsFPR(reg))
2101e209fccSTamas Berghammer     {
211068f8a7eSTamas Berghammer         error = ReadFPR();
212068f8a7eSTamas Berghammer         if (error.Fail())
2131e209fccSTamas Berghammer             return error;
2141e209fccSTamas Berghammer     }
2151e209fccSTamas Berghammer     else
2161e209fccSTamas Berghammer     {
2171e209fccSTamas Berghammer         uint32_t full_reg = reg;
2181e209fccSTamas Berghammer         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
2191e209fccSTamas Berghammer 
2201e209fccSTamas Berghammer         if (is_subreg)
2211e209fccSTamas Berghammer         {
2221e209fccSTamas Berghammer             // Read the full aligned 64-bit register.
2231e209fccSTamas Berghammer             full_reg = reg_info->invalidate_regs[0];
2241e209fccSTamas Berghammer         }
2251e209fccSTamas Berghammer 
2261e209fccSTamas Berghammer         error = ReadRegisterRaw(full_reg, reg_value);
2271e209fccSTamas Berghammer 
2281e209fccSTamas Berghammer         if (error.Success ())
2291e209fccSTamas Berghammer         {
2301e209fccSTamas Berghammer             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
2311e209fccSTamas Berghammer             if (is_subreg && (reg_info->byte_offset & 0x1))
2321e209fccSTamas Berghammer                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
2331e209fccSTamas Berghammer 
2341e209fccSTamas Berghammer             // If our return byte size was greater than the return value reg size, then
2351e209fccSTamas Berghammer             // use the type specified by reg_info rather than the uint64_t default
2361e209fccSTamas Berghammer             if (reg_value.GetByteSize() > reg_info->byte_size)
2371e209fccSTamas Berghammer                 reg_value.SetType(reg_info);
2381e209fccSTamas Berghammer         }
2391e209fccSTamas Berghammer         return error;
2401e209fccSTamas Berghammer     }
2411e209fccSTamas Berghammer 
2421e209fccSTamas Berghammer     // Get pointer to m_fpr variable and set the data from it.
2431e209fccSTamas Berghammer     assert (reg_info->byte_offset < sizeof m_fpr);
2441e209fccSTamas Berghammer     uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
2451e209fccSTamas Berghammer     switch (reg_info->byte_size)
2461e209fccSTamas Berghammer     {
2471e209fccSTamas Berghammer         case 2:
2481e209fccSTamas Berghammer             reg_value.SetUInt16(*(uint16_t *)src);
2491e209fccSTamas Berghammer             break;
2501e209fccSTamas Berghammer         case 4:
2511e209fccSTamas Berghammer             reg_value.SetUInt32(*(uint32_t *)src);
2521e209fccSTamas Berghammer             break;
2531e209fccSTamas Berghammer         case 8:
2541e209fccSTamas Berghammer             reg_value.SetUInt64(*(uint64_t *)src);
2551e209fccSTamas Berghammer             break;
2561e209fccSTamas Berghammer         default:
2571e209fccSTamas Berghammer             assert(false && "Unhandled data size.");
2581e209fccSTamas Berghammer             error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
2591e209fccSTamas Berghammer             break;
2601e209fccSTamas Berghammer     }
2611e209fccSTamas Berghammer 
2621e209fccSTamas Berghammer     return error;
2631e209fccSTamas Berghammer }
2641e209fccSTamas Berghammer 
265db264a6dSTamas Berghammer Error
2661e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
2671e209fccSTamas Berghammer {
2681e209fccSTamas Berghammer     if (!reg_info)
2691e209fccSTamas Berghammer         return Error ("reg_info NULL");
2701e209fccSTamas Berghammer 
2711e209fccSTamas Berghammer     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
2721e209fccSTamas Berghammer     if (reg_index == LLDB_INVALID_REGNUM)
2731e209fccSTamas Berghammer         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
2741e209fccSTamas Berghammer 
2751e209fccSTamas Berghammer     if (IsGPR(reg_index))
2761e209fccSTamas Berghammer         return WriteRegisterRaw(reg_index, reg_value);
2771e209fccSTamas Berghammer 
2781e209fccSTamas Berghammer     if (IsFPR(reg_index))
2791e209fccSTamas Berghammer     {
2801e209fccSTamas Berghammer         // Get pointer to m_fpr variable and set the data to it.
2811e209fccSTamas Berghammer         assert (reg_info->byte_offset < sizeof(m_fpr));
2821e209fccSTamas Berghammer         uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
2831e209fccSTamas Berghammer         switch (reg_info->byte_size)
2841e209fccSTamas Berghammer         {
2851e209fccSTamas Berghammer             case 2:
2861e209fccSTamas Berghammer                 *(uint16_t *)dst = reg_value.GetAsUInt16();
2871e209fccSTamas Berghammer                 break;
2881e209fccSTamas Berghammer             case 4:
2891e209fccSTamas Berghammer                 *(uint32_t *)dst = reg_value.GetAsUInt32();
2901e209fccSTamas Berghammer                 break;
2911e209fccSTamas Berghammer             case 8:
2921e209fccSTamas Berghammer                 *(uint64_t *)dst = reg_value.GetAsUInt64();
2931e209fccSTamas Berghammer                 break;
2941e209fccSTamas Berghammer             default:
2951e209fccSTamas Berghammer                 assert(false && "Unhandled data size.");
2961e209fccSTamas Berghammer                 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
2971e209fccSTamas Berghammer         }
2981e209fccSTamas Berghammer 
299068f8a7eSTamas Berghammer         Error error = WriteFPR();
300068f8a7eSTamas Berghammer         if (error.Fail())
301068f8a7eSTamas Berghammer             return error;
3021e209fccSTamas Berghammer 
3031e209fccSTamas Berghammer         return Error ();
3041e209fccSTamas Berghammer     }
3051e209fccSTamas Berghammer 
3061e209fccSTamas Berghammer     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
3071e209fccSTamas Berghammer }
3081e209fccSTamas Berghammer 
309db264a6dSTamas Berghammer Error
3101e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
3111e209fccSTamas Berghammer {
3121e209fccSTamas Berghammer     Error error;
3131e209fccSTamas Berghammer 
314db264a6dSTamas Berghammer     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
3151e209fccSTamas Berghammer     if (!data_sp)
3161e209fccSTamas Berghammer         return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
3171e209fccSTamas Berghammer 
318068f8a7eSTamas Berghammer     error = ReadGPR();
319068f8a7eSTamas Berghammer     if (error.Fail())
3201e209fccSTamas Berghammer         return error;
3211e209fccSTamas Berghammer 
322068f8a7eSTamas Berghammer     error = ReadFPR();
323068f8a7eSTamas Berghammer     if (error.Fail())
3241e209fccSTamas Berghammer         return error;
3251e209fccSTamas Berghammer 
3261e209fccSTamas Berghammer     uint8_t *dst = data_sp->GetBytes ();
3271e209fccSTamas Berghammer     if (dst == nullptr)
3281e209fccSTamas Berghammer     {
3291e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
3301e209fccSTamas Berghammer         return error;
3311e209fccSTamas Berghammer     }
3321e209fccSTamas Berghammer 
3331e209fccSTamas Berghammer     ::memcpy (dst, &m_gpr_arm64, GetGPRSize());
3341e209fccSTamas Berghammer     dst += GetGPRSize();
3351e209fccSTamas Berghammer     ::memcpy (dst, &m_fpr, sizeof(m_fpr));
3361e209fccSTamas Berghammer 
3371e209fccSTamas Berghammer     return error;
3381e209fccSTamas Berghammer }
3391e209fccSTamas Berghammer 
340db264a6dSTamas Berghammer Error
3411e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
3421e209fccSTamas Berghammer {
3431e209fccSTamas Berghammer     Error error;
3441e209fccSTamas Berghammer 
3451e209fccSTamas Berghammer     if (!data_sp)
3461e209fccSTamas Berghammer     {
3471e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
3481e209fccSTamas Berghammer         return error;
3491e209fccSTamas Berghammer     }
3501e209fccSTamas Berghammer 
3511e209fccSTamas Berghammer     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
3521e209fccSTamas Berghammer     {
3531e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
3541e209fccSTamas Berghammer         return error;
3551e209fccSTamas Berghammer     }
3561e209fccSTamas Berghammer 
3571e209fccSTamas Berghammer 
3581e209fccSTamas Berghammer     uint8_t *src = data_sp->GetBytes ();
3591e209fccSTamas Berghammer     if (src == nullptr)
3601e209fccSTamas Berghammer     {
3611e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
3621e209fccSTamas Berghammer         return error;
3631e209fccSTamas Berghammer     }
3641e209fccSTamas Berghammer     ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ());
3651e209fccSTamas Berghammer 
366068f8a7eSTamas Berghammer     error = WriteGPR();
367068f8a7eSTamas Berghammer     if (error.Fail())
3681e209fccSTamas Berghammer         return error;
3691e209fccSTamas Berghammer 
3701e209fccSTamas Berghammer     src += GetRegisterInfoInterface ().GetGPRSize ();
3711e209fccSTamas Berghammer     ::memcpy (&m_fpr, src, sizeof(m_fpr));
3721e209fccSTamas Berghammer 
373068f8a7eSTamas Berghammer     error = WriteFPR();
3741e209fccSTamas Berghammer     if (error.Fail())
3751e209fccSTamas Berghammer         return error;
3761e209fccSTamas Berghammer 
3771e209fccSTamas Berghammer     return error;
3781e209fccSTamas Berghammer }
3791e209fccSTamas Berghammer 
3801e209fccSTamas Berghammer bool
3811e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const
3821e209fccSTamas Berghammer {
3831e209fccSTamas Berghammer     return reg <= m_reg_info.last_gpr;   // GPR's come first.
3841e209fccSTamas Berghammer }
3851e209fccSTamas Berghammer 
3861e209fccSTamas Berghammer bool
3871e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const
3881e209fccSTamas Berghammer {
3891e209fccSTamas Berghammer     return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
3901e209fccSTamas Berghammer }
3911e209fccSTamas Berghammer 
392ea8c25a8SOmair Javaid uint32_t
393ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
394ea8c25a8SOmair Javaid {
395ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
396ea8c25a8SOmair Javaid 
397ea8c25a8SOmair Javaid     if (log)
398ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
399ea8c25a8SOmair Javaid 
400ea8c25a8SOmair Javaid     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
401ea8c25a8SOmair Javaid     if (!process_sp)
402ea8c25a8SOmair Javaid         return false;
403ea8c25a8SOmair Javaid 
404ea8c25a8SOmair Javaid     // Check if our hardware breakpoint and watchpoint information is updated.
405ea8c25a8SOmair Javaid     if (m_refresh_hwdebug_info)
406ea8c25a8SOmair Javaid     {
407068f8a7eSTamas Berghammer         ReadHardwareDebugInfo (m_max_hwp_supported, m_max_hbp_supported);
408ea8c25a8SOmair Javaid         m_refresh_hwdebug_info = false;
409ea8c25a8SOmair Javaid     }
410ea8c25a8SOmair Javaid 
411ea8c25a8SOmair Javaid     uint32_t control_value, bp_index;
412ea8c25a8SOmair Javaid 
413ea8c25a8SOmair Javaid     // Check if size has a valid hardware breakpoint length.
414ea8c25a8SOmair Javaid     if (size != 4)
415ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32;  // Invalid size for a AArch64 hardware breakpoint
416ea8c25a8SOmair Javaid 
417ea8c25a8SOmair Javaid     // Check 4-byte alignment for hardware breakpoint target address.
418ea8c25a8SOmair Javaid     if (addr & 0x03)
419ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
420ea8c25a8SOmair Javaid 
421ea8c25a8SOmair Javaid     // Setup control value
422ea8c25a8SOmair Javaid     control_value = 0;
423ea8c25a8SOmair Javaid     control_value |= ((1 << size) - 1) << 5;
424ea8c25a8SOmair Javaid     control_value |= (2 << 1) | 1;
425ea8c25a8SOmair Javaid 
426ea8c25a8SOmair Javaid     // Iterate over stored hardware breakpoints
427ea8c25a8SOmair Javaid     // Find a free bp_index or update reference count if duplicate.
428ea8c25a8SOmair Javaid     bp_index = LLDB_INVALID_INDEX32;
429ea8c25a8SOmair Javaid     for (uint32_t i = 0; i < m_max_hbp_supported; i++)
430ea8c25a8SOmair Javaid     {
431ea8c25a8SOmair Javaid         if ((m_hbr_regs[i].control & 1) == 0)
432ea8c25a8SOmair Javaid         {
433ea8c25a8SOmair Javaid             bp_index = i;  // Mark last free slot
434ea8c25a8SOmair Javaid         }
435ea8c25a8SOmair Javaid         else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
436ea8c25a8SOmair Javaid         {
437ea8c25a8SOmair Javaid             bp_index = i;  // Mark duplicate index
438ea8c25a8SOmair Javaid             break;  // Stop searching here
439ea8c25a8SOmair Javaid         }
440ea8c25a8SOmair Javaid     }
441ea8c25a8SOmair Javaid 
442ea8c25a8SOmair Javaid      if (bp_index == LLDB_INVALID_INDEX32)
443ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32;
444ea8c25a8SOmair Javaid 
445ea8c25a8SOmair Javaid     // Add new or update existing watchpoint
446ea8c25a8SOmair Javaid     if ((m_hbr_regs[bp_index].control & 1) == 0)
447ea8c25a8SOmair Javaid     {
448ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].address = addr;
449ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].control = control_value;
450ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].refcount = 1;
451ea8c25a8SOmair Javaid 
452ea8c25a8SOmair Javaid         //TODO: PTRACE CALL HERE for an UPDATE
453ea8c25a8SOmair Javaid     }
454ea8c25a8SOmair Javaid     else
455ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].refcount++;
456ea8c25a8SOmair Javaid 
457ea8c25a8SOmair Javaid     return bp_index;
458ea8c25a8SOmair Javaid }
459ea8c25a8SOmair Javaid 
460ea8c25a8SOmair Javaid bool
461ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx)
462ea8c25a8SOmair Javaid {
463ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
464ea8c25a8SOmair Javaid 
465ea8c25a8SOmair Javaid     if (log)
466ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
467ea8c25a8SOmair Javaid 
468ea8c25a8SOmair Javaid     if (hw_idx >= m_max_hbp_supported)
469ea8c25a8SOmair Javaid         return false;
470ea8c25a8SOmair Javaid 
471ea8c25a8SOmair Javaid     // Update reference count if multiple references.
472ea8c25a8SOmair Javaid     if (m_hbr_regs[hw_idx].refcount > 1)
473ea8c25a8SOmair Javaid     {
474ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].refcount--;
475ea8c25a8SOmair Javaid         return true;
476ea8c25a8SOmair Javaid     }
477ea8c25a8SOmair Javaid     else if (m_hbr_regs[hw_idx].refcount == 1)
478ea8c25a8SOmair Javaid     {
479ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].control &= ~1;
480ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].address = 0;
481ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].refcount = 0;
482ea8c25a8SOmair Javaid 
483ea8c25a8SOmair Javaid         //TODO: PTRACE CALL HERE for an UPDATE
484ea8c25a8SOmair Javaid         return true;
485ea8c25a8SOmair Javaid     }
486ea8c25a8SOmair Javaid 
487ea8c25a8SOmair Javaid     return false;
488ea8c25a8SOmair Javaid }
489ea8c25a8SOmair Javaid 
490ea8c25a8SOmair Javaid uint32_t
491ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints ()
492ea8c25a8SOmair Javaid {
493ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
494ea8c25a8SOmair Javaid 
495ea8c25a8SOmair Javaid     if (log)
496ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
497ea8c25a8SOmair Javaid 
498ea8c25a8SOmair Javaid     return m_max_hwp_supported;
499ea8c25a8SOmair Javaid }
500ea8c25a8SOmair Javaid 
501ea8c25a8SOmair Javaid uint32_t
502ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
503ea8c25a8SOmair Javaid {
504ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
505ea8c25a8SOmair Javaid 
506ea8c25a8SOmair Javaid     if (log)
507ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
508ea8c25a8SOmair Javaid 
509ea8c25a8SOmair Javaid     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
510ea8c25a8SOmair Javaid     if (!process_sp)
511ea8c25a8SOmair Javaid         return false;
512ea8c25a8SOmair Javaid 
513068f8a7eSTamas Berghammer 
514ea8c25a8SOmair Javaid     // Check if our hardware breakpoint and watchpoint information is updated.
515ea8c25a8SOmair Javaid     if (m_refresh_hwdebug_info)
516ea8c25a8SOmair Javaid     {
517068f8a7eSTamas Berghammer         ReadHardwareDebugInfo (m_max_hwp_supported, m_max_hbp_supported);
518ea8c25a8SOmair Javaid         m_refresh_hwdebug_info = false;
519ea8c25a8SOmair Javaid     }
520ea8c25a8SOmair Javaid 
521ea8c25a8SOmair Javaid     uint32_t control_value, wp_index;
522ea8c25a8SOmair Javaid 
523ea8c25a8SOmair Javaid 
524ea8c25a8SOmair Javaid     if (watch_flags != 0x1 && watch_flags != 0x2 && watch_flags != 0x3)
525ea8c25a8SOmair Javaid         return 0;//Error ("Invalid read/write bits for watchpoint");
526ea8c25a8SOmair Javaid 
527ea8c25a8SOmair Javaid     // Check if size has a valid hardware watchpoint length.
528ea8c25a8SOmair Javaid     if (size != 1 && size != 2 && size != 4 && size != 8)
529ea8c25a8SOmair Javaid         return 0;//Error ("Invalid size for watchpoint");
530ea8c25a8SOmair Javaid 
531ea8c25a8SOmair Javaid     // Check 8-byte alignment for hardware watchpoint target address.
532ea8c25a8SOmair Javaid     // TODO: Add support for watching un-aligned addresses
533ea8c25a8SOmair Javaid     if (addr & 0x07)
534ea8c25a8SOmair Javaid         return 0;//Error ("LLDB for AArch64 currently supports 8-byte alignment for hardware watchpoint target address.");
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;
544ea8c25a8SOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
545ea8c25a8SOmair Javaid     {
546ea8c25a8SOmair Javaid         if ((m_hwp_regs[i].control & 1) == 0)
547ea8c25a8SOmair Javaid         {
548ea8c25a8SOmair Javaid             wp_index = i; // Mark last free slot
549ea8c25a8SOmair Javaid         }
550ea8c25a8SOmair Javaid         else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
551ea8c25a8SOmair Javaid         {
552ea8c25a8SOmair Javaid             wp_index = i; // Mark duplicate index
553ea8c25a8SOmair Javaid             break; // Stop searching here
554ea8c25a8SOmair Javaid         }
555ea8c25a8SOmair Javaid     }
556ea8c25a8SOmair Javaid 
557ea8c25a8SOmair Javaid      if (wp_index == LLDB_INVALID_INDEX32)
558ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32;
559ea8c25a8SOmair Javaid 
560ea8c25a8SOmair Javaid     // Add new or update existing watchpoint
561ea8c25a8SOmair Javaid     if ((m_hwp_regs[wp_index].control & 1) == 0)
562ea8c25a8SOmair Javaid     {
563ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].address = addr;
564ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].control = control_value;
565ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount = 1;
566ea8c25a8SOmair Javaid 
567ea8c25a8SOmair Javaid         // PTRACE call to set corresponding watchpoint register.
568068f8a7eSTamas Berghammer         WriteHardwareDebugRegs(&addr, &control_value, 0, wp_index);
569ea8c25a8SOmair Javaid     }
570ea8c25a8SOmair Javaid     else
571ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount++;
572ea8c25a8SOmair Javaid 
573ea8c25a8SOmair Javaid     return wp_index;
574ea8c25a8SOmair Javaid }
575ea8c25a8SOmair Javaid 
576ea8c25a8SOmair Javaid bool
577ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index)
578ea8c25a8SOmair Javaid {
579ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
580ea8c25a8SOmair Javaid 
581ea8c25a8SOmair Javaid     if (log)
582ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
583ea8c25a8SOmair Javaid 
584ea8c25a8SOmair Javaid     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
585ea8c25a8SOmair Javaid     if (!process_sp)
586ea8c25a8SOmair Javaid         return false;
587ea8c25a8SOmair Javaid 
588ea8c25a8SOmair Javaid     if (wp_index >= m_max_hwp_supported)
589ea8c25a8SOmair Javaid         return false;
590ea8c25a8SOmair Javaid 
591ea8c25a8SOmair Javaid     // Update reference count if multiple references.
592ea8c25a8SOmair Javaid     if (m_hwp_regs[wp_index].refcount > 1)
593ea8c25a8SOmair Javaid     {
594ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount--;
595ea8c25a8SOmair Javaid         return true;
596ea8c25a8SOmair Javaid     }
597ea8c25a8SOmair Javaid     else if (m_hwp_regs[wp_index].refcount == 1)
598ea8c25a8SOmair Javaid     {
599ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].control &= ~1;
600ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].address = 0;
601ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount = 0;
602ea8c25a8SOmair Javaid 
603ea8c25a8SOmair Javaid         //TODO: PTRACE CALL HERE for an UPDATE
604068f8a7eSTamas Berghammer         WriteHardwareDebugRegs(&m_hwp_regs[wp_index].address, &m_hwp_regs[wp_index].control, 0, wp_index);
605ea8c25a8SOmair Javaid         return true;
606ea8c25a8SOmair Javaid     }
607ea8c25a8SOmair Javaid 
608ea8c25a8SOmair Javaid     return false;
609ea8c25a8SOmair Javaid }
610ea8c25a8SOmair Javaid 
611ea8c25a8SOmair Javaid Error
612ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints ()
613ea8c25a8SOmair Javaid {
614ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
615ea8c25a8SOmair Javaid 
616ea8c25a8SOmair Javaid     if (log)
617ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
618ea8c25a8SOmair Javaid 
619ea8c25a8SOmair Javaid     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
620ea8c25a8SOmair Javaid 
621ea8c25a8SOmair Javaid     Error ml_error;
622ea8c25a8SOmair Javaid     ml_error.SetErrorToErrno();
623ea8c25a8SOmair Javaid     if (!process_sp)
624ea8c25a8SOmair Javaid         return ml_error;
625ea8c25a8SOmair Javaid 
626ea8c25a8SOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
627ea8c25a8SOmair Javaid     {
628ea8c25a8SOmair Javaid         if (m_hwp_regs[i].control & 0x01)
629ea8c25a8SOmair Javaid         {
630ea8c25a8SOmair Javaid             m_hwp_regs[i].control &= ~1;
631ea8c25a8SOmair Javaid             m_hwp_regs[i].address = 0;
632ea8c25a8SOmair Javaid             m_hwp_regs[i].refcount = 0;
633ea8c25a8SOmair Javaid 
634068f8a7eSTamas Berghammer             WriteHardwareDebugRegs(&m_hwp_regs[i].address, &m_hwp_regs[i].control, 0, i);
635ea8c25a8SOmair Javaid         }
636ea8c25a8SOmair Javaid     }
637ea8c25a8SOmair Javaid 
638ea8c25a8SOmair Javaid     return Error();
639ea8c25a8SOmair Javaid }
640ea8c25a8SOmair Javaid 
641ea8c25a8SOmair Javaid uint32_t
642ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index)
643ea8c25a8SOmair Javaid {
644ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
645ea8c25a8SOmair Javaid 
646ea8c25a8SOmair Javaid     if (log)
647ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
648ea8c25a8SOmair Javaid     switch ((m_hwp_regs[wp_index].control >> 5) & 0xff)
649ea8c25a8SOmair Javaid     {
650ea8c25a8SOmair Javaid         case 0x01:
651ea8c25a8SOmair Javaid             return 1;
652ea8c25a8SOmair Javaid         case 0x03:
653ea8c25a8SOmair Javaid             return 2;
654ea8c25a8SOmair Javaid         case 0x0f:
655ea8c25a8SOmair Javaid             return 4;
656ea8c25a8SOmair Javaid         case 0xff:
657ea8c25a8SOmair Javaid             return 8;
658ea8c25a8SOmair Javaid         default:
659ea8c25a8SOmair Javaid             return 0;
660ea8c25a8SOmair Javaid     }
661ea8c25a8SOmair Javaid }
662ea8c25a8SOmair Javaid bool
663ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index)
664ea8c25a8SOmair Javaid {
665ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
666ea8c25a8SOmair Javaid 
667ea8c25a8SOmair Javaid     if (log)
668ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
669ea8c25a8SOmair Javaid 
670ea8c25a8SOmair Javaid     if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
671ea8c25a8SOmair Javaid         return true;
672ea8c25a8SOmair Javaid     else
673ea8c25a8SOmair Javaid         return false;
674ea8c25a8SOmair Javaid }
675ea8c25a8SOmair Javaid 
676ea8c25a8SOmair Javaid Error
677ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
678ea8c25a8SOmair Javaid {
679ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
680ea8c25a8SOmair Javaid 
681ea8c25a8SOmair Javaid     if (log)
682ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
683ea8c25a8SOmair Javaid 
684ea8c25a8SOmair Javaid     uint32_t watch_size;
685ea8c25a8SOmair Javaid     lldb::addr_t watch_addr;
686ea8c25a8SOmair Javaid 
687ea8c25a8SOmair Javaid     for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
688ea8c25a8SOmair Javaid     {
689ea8c25a8SOmair Javaid         watch_size = GetWatchpointSize (wp_index);
690ea8c25a8SOmair Javaid         watch_addr = m_hwp_regs[wp_index].address;
691ea8c25a8SOmair Javaid 
692ea8c25a8SOmair Javaid         if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
693ea8c25a8SOmair Javaid             && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
694ea8c25a8SOmair Javaid         {
695ea8c25a8SOmair Javaid             return Error();
696ea8c25a8SOmair Javaid         }
697ea8c25a8SOmair Javaid     }
698ea8c25a8SOmair Javaid 
699ea8c25a8SOmair Javaid     wp_index = LLDB_INVALID_INDEX32;
700ea8c25a8SOmair Javaid     return Error();
701ea8c25a8SOmair Javaid }
702ea8c25a8SOmair Javaid 
703ea8c25a8SOmair Javaid lldb::addr_t
704ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index)
705ea8c25a8SOmair Javaid {
706ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
707ea8c25a8SOmair Javaid 
708ea8c25a8SOmair Javaid     if (log)
709ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
710ea8c25a8SOmair Javaid 
711ea8c25a8SOmair Javaid     if (wp_index >= m_max_hwp_supported)
712ea8c25a8SOmair Javaid         return LLDB_INVALID_ADDRESS;
713ea8c25a8SOmair Javaid 
714ea8c25a8SOmair Javaid     if (WatchpointIsEnabled(wp_index))
715ea8c25a8SOmair Javaid         return m_hwp_regs[wp_index].address;
716ea8c25a8SOmair Javaid     else
717ea8c25a8SOmair Javaid         return LLDB_INVALID_ADDRESS;
718ea8c25a8SOmair Javaid }
719ea8c25a8SOmair Javaid 
720068f8a7eSTamas Berghammer Error
721068f8a7eSTamas Berghammer NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo(unsigned int &watch_count,
722068f8a7eSTamas Berghammer                                                         unsigned int &break_count)
723ea8c25a8SOmair Javaid {
724068f8a7eSTamas Berghammer     NativeProcessProtocolSP process_sp (m_thread.GetProcess());
725068f8a7eSTamas Berghammer     if (!process_sp)
726068f8a7eSTamas Berghammer         return Error("NativeProcessProtocol is NULL");
727068f8a7eSTamas Berghammer     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*>(process_sp.get());
728c7512fdcSPavel Labath     ::pid_t tid = m_thread.GetID();
729ea8c25a8SOmair Javaid 
730c7512fdcSPavel Labath     return process_p->DoOperation([&] {
731c7512fdcSPavel Labath         int regset = NT_ARM_HW_WATCH;
732c7512fdcSPavel Labath         struct iovec ioVec;
733c7512fdcSPavel Labath         struct user_hwdebug_state dreg_state;
734c7512fdcSPavel Labath         Error error;
735c7512fdcSPavel Labath 
736c7512fdcSPavel Labath         ioVec.iov_base = &dreg_state;
737c7512fdcSPavel Labath         ioVec.iov_len = sizeof (dreg_state);
738*4a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
739c7512fdcSPavel Labath         watch_count = dreg_state.dbg_info & 0xff;
740c7512fdcSPavel Labath 
741c7512fdcSPavel Labath         regset = NT_ARM_HW_BREAK;
742*4a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
743c7512fdcSPavel Labath         break_count = dreg_state.dbg_info & 0xff;
744c7512fdcSPavel Labath 
745c7512fdcSPavel Labath         return error;
746c7512fdcSPavel Labath     });
747ea8c25a8SOmair Javaid }
748068f8a7eSTamas Berghammer 
749068f8a7eSTamas Berghammer Error
750068f8a7eSTamas Berghammer NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(lldb::addr_t *addr_buf,
751068f8a7eSTamas Berghammer                                                          uint32_t *cntrl_buf,
752068f8a7eSTamas Berghammer                                                          int type,
753068f8a7eSTamas Berghammer                                                          int count)
754068f8a7eSTamas Berghammer {
755068f8a7eSTamas Berghammer     NativeProcessProtocolSP process_sp (m_thread.GetProcess());
756068f8a7eSTamas Berghammer     if (!process_sp)
757068f8a7eSTamas Berghammer         return Error("NativeProcessProtocol is NULL");
758068f8a7eSTamas Berghammer     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*>(process_sp.get());
759068f8a7eSTamas Berghammer 
760c7512fdcSPavel Labath     return process_p->DoOperation([&] {
761c7512fdcSPavel Labath         struct iovec ioVec;
762c7512fdcSPavel Labath         struct user_hwdebug_state dreg_state;
763c7512fdcSPavel Labath         Error error;
764c7512fdcSPavel Labath 
765c7512fdcSPavel Labath         memset (&dreg_state, 0, sizeof (dreg_state));
766c7512fdcSPavel Labath         ioVec.iov_base = &dreg_state;
767c7512fdcSPavel Labath         ioVec.iov_len = sizeof (dreg_state);
768c7512fdcSPavel Labath 
769c7512fdcSPavel Labath         if (type == 0)
770c7512fdcSPavel Labath             type = NT_ARM_HW_WATCH;
771c7512fdcSPavel Labath         else
772c7512fdcSPavel Labath             type = NT_ARM_HW_BREAK;
773c7512fdcSPavel Labath 
774c7512fdcSPavel Labath         for (int i = 0; i < count; i++)
775c7512fdcSPavel Labath         {
776c7512fdcSPavel Labath             dreg_state.dbg_regs[i].addr = addr_buf[i];
777c7512fdcSPavel Labath             dreg_state.dbg_regs[i].ctrl = cntrl_buf[i];
778068f8a7eSTamas Berghammer         }
779068f8a7eSTamas Berghammer 
780*4a9babb2SPavel Labath         return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &type, &ioVec, ioVec.iov_len);
781c7512fdcSPavel Labath     });
782c7512fdcSPavel Labath }
783c7512fdcSPavel Labath 
784c7512fdcSPavel Labath Error
785c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset,
786068f8a7eSTamas Berghammer                                                       const char* reg_name,
787068f8a7eSTamas Berghammer                                                       uint32_t size,
788068f8a7eSTamas Berghammer                                                       RegisterValue &value)
789068f8a7eSTamas Berghammer {
790c7512fdcSPavel Labath     Error error;
791c7512fdcSPavel Labath     if (offset > sizeof(struct user_pt_regs))
792c7512fdcSPavel Labath     {
793c7512fdcSPavel Labath         uintptr_t offset = offset - sizeof(struct user_pt_regs);
794c7512fdcSPavel Labath         if (offset > sizeof(struct user_fpsimd_state))
795c7512fdcSPavel Labath         {
796c7512fdcSPavel Labath             error.SetErrorString("invalid offset value");
797c7512fdcSPavel Labath             return error;
798c7512fdcSPavel Labath         }
799c7512fdcSPavel Labath         elf_fpregset_t regs;
800c7512fdcSPavel Labath         int regset = NT_FPREGSET;
801c7512fdcSPavel Labath         struct iovec ioVec;
802c7512fdcSPavel Labath 
803c7512fdcSPavel Labath         ioVec.iov_base = &regs;
804c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
805*4a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper(
806*4a9babb2SPavel Labath                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
807c7512fdcSPavel Labath         if (error.Success())
808c7512fdcSPavel Labath         {
809c7512fdcSPavel Labath             ArchSpec arch;
810c7512fdcSPavel Labath             if (m_thread.GetProcess()->GetArchitecture(arch))
811c7512fdcSPavel Labath                 value.SetBytes((void *)(((unsigned char *)(&regs)) + offset), 16, arch.GetByteOrder());
812c7512fdcSPavel Labath             else
813c7512fdcSPavel Labath                 error.SetErrorString("failed to get architecture");
814c7512fdcSPavel Labath         }
815c7512fdcSPavel Labath     }
816c7512fdcSPavel Labath     else
817c7512fdcSPavel Labath     {
818c7512fdcSPavel Labath         elf_gregset_t regs;
819c7512fdcSPavel Labath         int regset = NT_PRSTATUS;
820c7512fdcSPavel Labath         struct iovec ioVec;
821c7512fdcSPavel Labath 
822c7512fdcSPavel Labath         ioVec.iov_base = &regs;
823c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
824*4a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper(
825*4a9babb2SPavel Labath                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
826c7512fdcSPavel Labath         if (error.Success())
827c7512fdcSPavel Labath         {
828c7512fdcSPavel Labath             ArchSpec arch;
829c7512fdcSPavel Labath             if (m_thread.GetProcess()->GetArchitecture(arch))
830c7512fdcSPavel Labath                 value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder());
831c7512fdcSPavel Labath             else
832c7512fdcSPavel Labath                 error.SetErrorString("failed to get architecture");
833c7512fdcSPavel Labath         }
834c7512fdcSPavel Labath     }
835c7512fdcSPavel Labath     return error;
836068f8a7eSTamas Berghammer }
837068f8a7eSTamas Berghammer 
838c7512fdcSPavel Labath Error
839c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset,
840068f8a7eSTamas Berghammer                                                        const char* reg_name,
841068f8a7eSTamas Berghammer                                                        const RegisterValue &value)
842068f8a7eSTamas Berghammer {
843c7512fdcSPavel Labath     Error error;
844c7512fdcSPavel Labath     ::pid_t tid = m_thread.GetID();
845c7512fdcSPavel Labath     if (offset > sizeof(struct user_pt_regs))
846c7512fdcSPavel Labath     {
847c7512fdcSPavel Labath         uintptr_t offset = offset - sizeof(struct user_pt_regs);
848c7512fdcSPavel Labath         if (offset > sizeof(struct user_fpsimd_state))
849c7512fdcSPavel Labath         {
850c7512fdcSPavel Labath             error.SetErrorString("invalid offset value");
851c7512fdcSPavel Labath             return error;
852c7512fdcSPavel Labath         }
853c7512fdcSPavel Labath         elf_fpregset_t regs;
854c7512fdcSPavel Labath         int regset = NT_FPREGSET;
855c7512fdcSPavel Labath         struct iovec ioVec;
856c7512fdcSPavel Labath 
857c7512fdcSPavel Labath         ioVec.iov_base = &regs;
858c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
859*4a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
860c7512fdcSPavel Labath 
861c7512fdcSPavel Labath         if (error.Success())
862c7512fdcSPavel Labath         {
863c7512fdcSPavel Labath             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 16);
864*4a9babb2SPavel Labath             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
865c7512fdcSPavel Labath         }
866c7512fdcSPavel Labath     }
867c7512fdcSPavel Labath     else
868c7512fdcSPavel Labath     {
869c7512fdcSPavel Labath         elf_gregset_t regs;
870c7512fdcSPavel Labath         int regset = NT_PRSTATUS;
871c7512fdcSPavel Labath         struct iovec ioVec;
872c7512fdcSPavel Labath 
873c7512fdcSPavel Labath         ioVec.iov_base = &regs;
874c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
875*4a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
876c7512fdcSPavel Labath         if (error.Success())
877c7512fdcSPavel Labath         {
878c7512fdcSPavel Labath             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 8);
879*4a9babb2SPavel Labath             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
880c7512fdcSPavel Labath         }
881c7512fdcSPavel Labath     }
882c7512fdcSPavel Labath     return error;
883068f8a7eSTamas Berghammer }
884068f8a7eSTamas Berghammer 
885c7512fdcSPavel Labath Error
886c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size)
887068f8a7eSTamas Berghammer {
888c7512fdcSPavel Labath     int regset = NT_PRSTATUS;
889c7512fdcSPavel Labath     struct iovec ioVec;
890c7512fdcSPavel Labath     Error error;
891c7512fdcSPavel Labath 
892c7512fdcSPavel Labath     ioVec.iov_base = buf;
893c7512fdcSPavel Labath     ioVec.iov_len = buf_size;
894*4a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
895068f8a7eSTamas Berghammer }
896068f8a7eSTamas Berghammer 
897c7512fdcSPavel Labath Error
898c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size)
899068f8a7eSTamas Berghammer {
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;
906*4a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
907068f8a7eSTamas Berghammer }
908068f8a7eSTamas Berghammer 
909c7512fdcSPavel Labath Error
910c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size)
911068f8a7eSTamas Berghammer {
912c7512fdcSPavel Labath     int regset = NT_FPREGSET;
913c7512fdcSPavel Labath     struct iovec ioVec;
914c7512fdcSPavel Labath     Error error;
915c7512fdcSPavel Labath 
916c7512fdcSPavel Labath     ioVec.iov_base = buf;
917c7512fdcSPavel Labath     ioVec.iov_len = buf_size;
918*4a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
919068f8a7eSTamas Berghammer }
920068f8a7eSTamas Berghammer 
921c7512fdcSPavel Labath Error
922c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size)
923068f8a7eSTamas Berghammer {
924c7512fdcSPavel Labath     int regset = NT_FPREGSET;
925c7512fdcSPavel Labath     struct iovec ioVec;
926c7512fdcSPavel Labath     Error error;
927c7512fdcSPavel Labath 
928c7512fdcSPavel Labath     ioVec.iov_base = buf;
929c7512fdcSPavel Labath     ioVec.iov_len = buf_size;
930*4a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
931068f8a7eSTamas Berghammer }
932068f8a7eSTamas Berghammer 
933068f8a7eSTamas Berghammer #endif // defined (__arm64__) || defined (__aarch64__)
934