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 
196cec93c35STamas Berghammer uint32_t
197cec93c35STamas Berghammer NativeRegisterContextLinux_arm64::GetUserRegisterCount() const
198cec93c35STamas Berghammer {
199cec93c35STamas Berghammer     uint32_t count = 0;
200cec93c35STamas Berghammer     for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
201cec93c35STamas Berghammer         count += g_reg_sets_arm64[set_index].num_registers;
202cec93c35STamas Berghammer     return count;
203cec93c35STamas Berghammer }
204cec93c35STamas Berghammer 
205db264a6dSTamas Berghammer Error
2061e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
2071e209fccSTamas Berghammer {
2081e209fccSTamas Berghammer     Error error;
2091e209fccSTamas Berghammer 
2101e209fccSTamas Berghammer     if (!reg_info)
2111e209fccSTamas Berghammer     {
2121e209fccSTamas Berghammer         error.SetErrorString ("reg_info NULL");
2131e209fccSTamas Berghammer         return error;
2141e209fccSTamas Berghammer     }
2151e209fccSTamas Berghammer 
2161e209fccSTamas Berghammer     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
2171e209fccSTamas Berghammer 
2181e209fccSTamas Berghammer     if (IsFPR(reg))
2191e209fccSTamas Berghammer     {
220068f8a7eSTamas Berghammer         error = ReadFPR();
221068f8a7eSTamas Berghammer         if (error.Fail())
2221e209fccSTamas Berghammer             return error;
2231e209fccSTamas Berghammer     }
2241e209fccSTamas Berghammer     else
2251e209fccSTamas Berghammer     {
2261e209fccSTamas Berghammer         uint32_t full_reg = reg;
2271e209fccSTamas Berghammer         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
2281e209fccSTamas Berghammer 
2291e209fccSTamas Berghammer         if (is_subreg)
2301e209fccSTamas Berghammer         {
2311e209fccSTamas Berghammer             // Read the full aligned 64-bit register.
2321e209fccSTamas Berghammer             full_reg = reg_info->invalidate_regs[0];
2331e209fccSTamas Berghammer         }
2341e209fccSTamas Berghammer 
2351e209fccSTamas Berghammer         error = ReadRegisterRaw(full_reg, reg_value);
2361e209fccSTamas Berghammer 
2371e209fccSTamas Berghammer         if (error.Success ())
2381e209fccSTamas Berghammer         {
2391e209fccSTamas Berghammer             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
2401e209fccSTamas Berghammer             if (is_subreg && (reg_info->byte_offset & 0x1))
2411e209fccSTamas Berghammer                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
2421e209fccSTamas Berghammer 
2431e209fccSTamas Berghammer             // If our return byte size was greater than the return value reg size, then
2441e209fccSTamas Berghammer             // use the type specified by reg_info rather than the uint64_t default
2451e209fccSTamas Berghammer             if (reg_value.GetByteSize() > reg_info->byte_size)
2461e209fccSTamas Berghammer                 reg_value.SetType(reg_info);
2471e209fccSTamas Berghammer         }
2481e209fccSTamas Berghammer         return error;
2491e209fccSTamas Berghammer     }
2501e209fccSTamas Berghammer 
2511e209fccSTamas Berghammer     // Get pointer to m_fpr variable and set the data from it.
2521e209fccSTamas Berghammer     assert (reg_info->byte_offset < sizeof m_fpr);
2531e209fccSTamas Berghammer     uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
254cec93c35STamas Berghammer     reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, eByteOrderLittle, error);
2551e209fccSTamas Berghammer 
2561e209fccSTamas Berghammer     return error;
2571e209fccSTamas Berghammer }
2581e209fccSTamas Berghammer 
259db264a6dSTamas Berghammer Error
2601e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
2611e209fccSTamas Berghammer {
2621e209fccSTamas Berghammer     if (!reg_info)
2631e209fccSTamas Berghammer         return Error ("reg_info NULL");
2641e209fccSTamas Berghammer 
2651e209fccSTamas Berghammer     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
2661e209fccSTamas Berghammer     if (reg_index == LLDB_INVALID_REGNUM)
2671e209fccSTamas Berghammer         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
2681e209fccSTamas Berghammer 
2691e209fccSTamas Berghammer     if (IsGPR(reg_index))
2701e209fccSTamas Berghammer         return WriteRegisterRaw(reg_index, reg_value);
2711e209fccSTamas Berghammer 
2721e209fccSTamas Berghammer     if (IsFPR(reg_index))
2731e209fccSTamas Berghammer     {
2741e209fccSTamas Berghammer         // Get pointer to m_fpr variable and set the data to it.
2751e209fccSTamas Berghammer         assert (reg_info->byte_offset < sizeof(m_fpr));
2761e209fccSTamas Berghammer         uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
2771e209fccSTamas Berghammer         switch (reg_info->byte_size)
2781e209fccSTamas Berghammer         {
2791e209fccSTamas Berghammer             case 2:
2801e209fccSTamas Berghammer                 *(uint16_t *)dst = reg_value.GetAsUInt16();
2811e209fccSTamas Berghammer                 break;
2821e209fccSTamas Berghammer             case 4:
2831e209fccSTamas Berghammer                 *(uint32_t *)dst = reg_value.GetAsUInt32();
2841e209fccSTamas Berghammer                 break;
2851e209fccSTamas Berghammer             case 8:
2861e209fccSTamas Berghammer                 *(uint64_t *)dst = reg_value.GetAsUInt64();
2871e209fccSTamas Berghammer                 break;
2881e209fccSTamas Berghammer             default:
2891e209fccSTamas Berghammer                 assert(false && "Unhandled data size.");
2901e209fccSTamas Berghammer                 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
2911e209fccSTamas Berghammer         }
2921e209fccSTamas Berghammer 
293068f8a7eSTamas Berghammer         Error error = WriteFPR();
294068f8a7eSTamas Berghammer         if (error.Fail())
295068f8a7eSTamas Berghammer             return error;
2961e209fccSTamas Berghammer 
2971e209fccSTamas Berghammer         return Error ();
2981e209fccSTamas Berghammer     }
2991e209fccSTamas Berghammer 
3001e209fccSTamas Berghammer     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
3011e209fccSTamas Berghammer }
3021e209fccSTamas Berghammer 
303db264a6dSTamas Berghammer Error
3041e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
3051e209fccSTamas Berghammer {
3061e209fccSTamas Berghammer     Error error;
3071e209fccSTamas Berghammer 
308db264a6dSTamas Berghammer     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
3091e209fccSTamas Berghammer     if (!data_sp)
3101e209fccSTamas Berghammer         return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
3111e209fccSTamas Berghammer 
312068f8a7eSTamas Berghammer     error = ReadGPR();
313068f8a7eSTamas Berghammer     if (error.Fail())
3141e209fccSTamas Berghammer         return error;
3151e209fccSTamas Berghammer 
316068f8a7eSTamas Berghammer     error = ReadFPR();
317068f8a7eSTamas Berghammer     if (error.Fail())
3181e209fccSTamas Berghammer         return error;
3191e209fccSTamas Berghammer 
3201e209fccSTamas Berghammer     uint8_t *dst = data_sp->GetBytes ();
3211e209fccSTamas Berghammer     if (dst == nullptr)
3221e209fccSTamas Berghammer     {
3231e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
3241e209fccSTamas Berghammer         return error;
3251e209fccSTamas Berghammer     }
3261e209fccSTamas Berghammer 
3271e209fccSTamas Berghammer     ::memcpy (dst, &m_gpr_arm64, GetGPRSize());
3281e209fccSTamas Berghammer     dst += GetGPRSize();
3291e209fccSTamas Berghammer     ::memcpy (dst, &m_fpr, sizeof(m_fpr));
3301e209fccSTamas Berghammer 
3311e209fccSTamas Berghammer     return error;
3321e209fccSTamas Berghammer }
3331e209fccSTamas Berghammer 
334db264a6dSTamas Berghammer Error
3351e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
3361e209fccSTamas Berghammer {
3371e209fccSTamas Berghammer     Error error;
3381e209fccSTamas Berghammer 
3391e209fccSTamas Berghammer     if (!data_sp)
3401e209fccSTamas Berghammer     {
3411e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
3421e209fccSTamas Berghammer         return error;
3431e209fccSTamas Berghammer     }
3441e209fccSTamas Berghammer 
3451e209fccSTamas Berghammer     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
3461e209fccSTamas Berghammer     {
3471e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
3481e209fccSTamas Berghammer         return error;
3491e209fccSTamas Berghammer     }
3501e209fccSTamas Berghammer 
3511e209fccSTamas Berghammer 
3521e209fccSTamas Berghammer     uint8_t *src = data_sp->GetBytes ();
3531e209fccSTamas Berghammer     if (src == nullptr)
3541e209fccSTamas Berghammer     {
3551e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
3561e209fccSTamas Berghammer         return error;
3571e209fccSTamas Berghammer     }
3581e209fccSTamas Berghammer     ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ());
3591e209fccSTamas Berghammer 
360068f8a7eSTamas Berghammer     error = WriteGPR();
361068f8a7eSTamas Berghammer     if (error.Fail())
3621e209fccSTamas Berghammer         return error;
3631e209fccSTamas Berghammer 
3641e209fccSTamas Berghammer     src += GetRegisterInfoInterface ().GetGPRSize ();
3651e209fccSTamas Berghammer     ::memcpy (&m_fpr, src, sizeof(m_fpr));
3661e209fccSTamas Berghammer 
367068f8a7eSTamas Berghammer     error = WriteFPR();
3681e209fccSTamas Berghammer     if (error.Fail())
3691e209fccSTamas Berghammer         return error;
3701e209fccSTamas Berghammer 
3711e209fccSTamas Berghammer     return error;
3721e209fccSTamas Berghammer }
3731e209fccSTamas Berghammer 
3741e209fccSTamas Berghammer bool
3751e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const
3761e209fccSTamas Berghammer {
3771e209fccSTamas Berghammer     return reg <= m_reg_info.last_gpr;   // GPR's come first.
3781e209fccSTamas Berghammer }
3791e209fccSTamas Berghammer 
3801e209fccSTamas Berghammer bool
3811e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const
3821e209fccSTamas Berghammer {
3831e209fccSTamas Berghammer     return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
3841e209fccSTamas Berghammer }
3851e209fccSTamas Berghammer 
386ea8c25a8SOmair Javaid uint32_t
387ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
388ea8c25a8SOmair Javaid {
389ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
390ea8c25a8SOmair Javaid 
391ea8c25a8SOmair Javaid     if (log)
392ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
393ea8c25a8SOmair Javaid 
394*3a56363aSOmair Javaid     Error error;
395ea8c25a8SOmair Javaid 
396*3a56363aSOmair Javaid     // Read hardware breakpoint and watchpoint information.
397*3a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
398*3a56363aSOmair Javaid 
399*3a56363aSOmair Javaid     if (error.Fail())
400*3a56363aSOmair Javaid         return LLDB_INVALID_INDEX32;
401*3a56363aSOmair Javaid 
402*3a56363aSOmair Javaid     uint32_t control_value = 0, bp_index = 0;
403ea8c25a8SOmair Javaid 
404ea8c25a8SOmair Javaid     // Check if size has a valid hardware breakpoint length.
405ea8c25a8SOmair Javaid     if (size != 4)
406ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32;  // Invalid size for a AArch64 hardware breakpoint
407ea8c25a8SOmair Javaid 
408ea8c25a8SOmair Javaid     // Check 4-byte alignment for hardware breakpoint target address.
409ea8c25a8SOmair Javaid     if (addr & 0x03)
410ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
411ea8c25a8SOmair Javaid 
412ea8c25a8SOmair Javaid     // Setup control value
413ea8c25a8SOmair Javaid     control_value = 0;
414ea8c25a8SOmair Javaid     control_value |= ((1 << size) - 1) << 5;
415ea8c25a8SOmair Javaid     control_value |= (2 << 1) | 1;
416ea8c25a8SOmair Javaid 
417ea8c25a8SOmair Javaid     // Iterate over stored hardware breakpoints
418ea8c25a8SOmair Javaid     // Find a free bp_index or update reference count if duplicate.
419ea8c25a8SOmair Javaid     bp_index = LLDB_INVALID_INDEX32;
420ea8c25a8SOmair Javaid     for (uint32_t i = 0; i < m_max_hbp_supported; i++)
421ea8c25a8SOmair Javaid     {
422ea8c25a8SOmair Javaid         if ((m_hbr_regs[i].control & 1) == 0)
423ea8c25a8SOmair Javaid         {
424ea8c25a8SOmair Javaid             bp_index = i;  // Mark last free slot
425ea8c25a8SOmair Javaid         }
426ea8c25a8SOmair Javaid         else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
427ea8c25a8SOmair Javaid         {
428ea8c25a8SOmair Javaid             bp_index = i;  // Mark duplicate index
429ea8c25a8SOmair Javaid             break;  // Stop searching here
430ea8c25a8SOmair Javaid         }
431ea8c25a8SOmair Javaid     }
432ea8c25a8SOmair Javaid 
433ea8c25a8SOmair Javaid      if (bp_index == LLDB_INVALID_INDEX32)
434ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32;
435ea8c25a8SOmair Javaid 
436ea8c25a8SOmair Javaid     // Add new or update existing watchpoint
437ea8c25a8SOmair Javaid     if ((m_hbr_regs[bp_index].control & 1) == 0)
438ea8c25a8SOmair Javaid     {
439ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].address = addr;
440ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].control = control_value;
441ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].refcount = 1;
442ea8c25a8SOmair Javaid 
4431fd2a8cfSOmair Javaid         // PTRACE call to set corresponding hardware breakpoint register.
444*3a56363aSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeBREAK);
445*3a56363aSOmair Javaid 
446*3a56363aSOmair Javaid         if (error.Fail())
447*3a56363aSOmair Javaid             return LLDB_INVALID_INDEX32;
448ea8c25a8SOmair Javaid     }
449ea8c25a8SOmair Javaid     else
450ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].refcount++;
451ea8c25a8SOmair Javaid 
452ea8c25a8SOmair Javaid     return bp_index;
453ea8c25a8SOmair Javaid }
454ea8c25a8SOmair Javaid 
455ea8c25a8SOmair Javaid bool
456ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx)
457ea8c25a8SOmair Javaid {
458ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
459ea8c25a8SOmair Javaid 
460ea8c25a8SOmair Javaid     if (log)
461ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
462ea8c25a8SOmair Javaid 
463*3a56363aSOmair Javaid     Error error;
464*3a56363aSOmair Javaid 
4651fd2a8cfSOmair Javaid     // Read hardware breakpoint and watchpoint information.
466*3a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
467*3a56363aSOmair Javaid 
468*3a56363aSOmair Javaid     if (error.Fail())
469*3a56363aSOmair Javaid         return false;
4701fd2a8cfSOmair Javaid 
471ea8c25a8SOmair Javaid     if (hw_idx >= m_max_hbp_supported)
472ea8c25a8SOmair Javaid         return false;
473ea8c25a8SOmair Javaid 
474ea8c25a8SOmair Javaid     // Update reference count if multiple references.
475ea8c25a8SOmair Javaid     if (m_hbr_regs[hw_idx].refcount > 1)
476ea8c25a8SOmair Javaid     {
477ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].refcount--;
478ea8c25a8SOmair Javaid         return true;
479ea8c25a8SOmair Javaid     }
480ea8c25a8SOmair Javaid     else if (m_hbr_regs[hw_idx].refcount == 1)
481ea8c25a8SOmair Javaid     {
482ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].control &= ~1;
483ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].address = 0;
484ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].refcount = 0;
485ea8c25a8SOmair Javaid 
4861fd2a8cfSOmair Javaid         // PTRACE call to clear corresponding hardware breakpoint register.
4871fd2a8cfSOmair Javaid         WriteHardwareDebugRegs(eDREGTypeBREAK);
488*3a56363aSOmair Javaid 
489*3a56363aSOmair Javaid         if (error.Fail())
490*3a56363aSOmair Javaid             return false;
491*3a56363aSOmair Javaid 
492*3a56363aSOmair Javaid         return true;
493ea8c25a8SOmair Javaid     }
494ea8c25a8SOmair Javaid 
495ea8c25a8SOmair Javaid     return false;
496ea8c25a8SOmair Javaid }
497ea8c25a8SOmair Javaid 
498ea8c25a8SOmair Javaid uint32_t
499ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints ()
500ea8c25a8SOmair Javaid {
501ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
502ea8c25a8SOmair Javaid 
503ea8c25a8SOmair Javaid     if (log)
504ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
505ea8c25a8SOmair Javaid 
506*3a56363aSOmair Javaid     Error error;
507*3a56363aSOmair Javaid 
5081fd2a8cfSOmair Javaid     // Read hardware breakpoint and watchpoint information.
509*3a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
510*3a56363aSOmair Javaid 
511*3a56363aSOmair Javaid     if (error.Fail())
512*3a56363aSOmair Javaid         return LLDB_INVALID_INDEX32;
5131fd2a8cfSOmair Javaid 
514ea8c25a8SOmair Javaid     return m_max_hwp_supported;
515ea8c25a8SOmair Javaid }
516ea8c25a8SOmair Javaid 
517ea8c25a8SOmair Javaid uint32_t
518ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
519ea8c25a8SOmair Javaid {
520ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
521ea8c25a8SOmair Javaid 
522ea8c25a8SOmair Javaid     if (log)
523ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
524ea8c25a8SOmair Javaid 
525*3a56363aSOmair Javaid     Error error;
526ea8c25a8SOmair Javaid 
527*3a56363aSOmair Javaid     // Read hardware breakpoint and watchpoint information.
528*3a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
529*3a56363aSOmair Javaid 
530*3a56363aSOmair Javaid     if (error.Fail())
531*3a56363aSOmair Javaid         return LLDB_INVALID_INDEX32;
532*3a56363aSOmair Javaid 
533*3a56363aSOmair Javaid     uint32_t control_value = 0, wp_index = 0;
534ea8c25a8SOmair Javaid 
5351fd2a8cfSOmair Javaid     // Check if we are setting watchpoint other than read/write/access
5361fd2a8cfSOmair Javaid     // Also update watchpoint flag to match AArch64 write-read bit configuration.
5371fd2a8cfSOmair Javaid     switch (watch_flags)
5381fd2a8cfSOmair Javaid     {
5391fd2a8cfSOmair Javaid         case 1:
5401fd2a8cfSOmair Javaid             watch_flags = 2;
5411fd2a8cfSOmair Javaid             break;
5421fd2a8cfSOmair Javaid         case 2:
5431fd2a8cfSOmair Javaid             watch_flags = 1;
5441fd2a8cfSOmair Javaid             break;
5451fd2a8cfSOmair Javaid         case 3:
5461fd2a8cfSOmair Javaid             break;
5471fd2a8cfSOmair Javaid         default:
5481fd2a8cfSOmair Javaid             return LLDB_INVALID_INDEX32;
5491fd2a8cfSOmair Javaid     }
550ea8c25a8SOmair Javaid 
551ea8c25a8SOmair Javaid     // Check if size has a valid hardware watchpoint length.
552ea8c25a8SOmair Javaid     if (size != 1 && size != 2 && size != 4 && size != 8)
5531fd2a8cfSOmair Javaid         return LLDB_INVALID_INDEX32;
554ea8c25a8SOmair Javaid 
555ea8c25a8SOmair Javaid     // Check 8-byte alignment for hardware watchpoint target address.
556ea8c25a8SOmair Javaid     // TODO: Add support for watching un-aligned addresses
557ea8c25a8SOmair Javaid     if (addr & 0x07)
5581fd2a8cfSOmair Javaid         return LLDB_INVALID_INDEX32;
559ea8c25a8SOmair Javaid 
560ea8c25a8SOmair Javaid     // Setup control value
561ea8c25a8SOmair Javaid     control_value = watch_flags << 3;
562ea8c25a8SOmair Javaid     control_value |= ((1 << size) - 1) << 5;
563ea8c25a8SOmair Javaid     control_value |= (2 << 1) | 1;
564ea8c25a8SOmair Javaid 
565ea8c25a8SOmair Javaid     // Iterate over stored watchpoints
566ea8c25a8SOmair Javaid     // Find a free wp_index or update reference count if duplicate.
567ea8c25a8SOmair Javaid     wp_index = LLDB_INVALID_INDEX32;
568ea8c25a8SOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
569ea8c25a8SOmair Javaid     {
570ea8c25a8SOmair Javaid         if ((m_hwp_regs[i].control & 1) == 0)
571ea8c25a8SOmair Javaid         {
572ea8c25a8SOmair Javaid             wp_index = i; // Mark last free slot
573ea8c25a8SOmair Javaid         }
574ea8c25a8SOmair Javaid         else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
575ea8c25a8SOmair Javaid         {
576ea8c25a8SOmair Javaid             wp_index = i; // Mark duplicate index
577ea8c25a8SOmair Javaid             break; // Stop searching here
578ea8c25a8SOmair Javaid         }
579ea8c25a8SOmair Javaid     }
580ea8c25a8SOmair Javaid 
581ea8c25a8SOmair Javaid      if (wp_index == LLDB_INVALID_INDEX32)
582ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32;
583ea8c25a8SOmair Javaid 
584ea8c25a8SOmair Javaid     // Add new or update existing watchpoint
585ea8c25a8SOmair Javaid     if ((m_hwp_regs[wp_index].control & 1) == 0)
586ea8c25a8SOmair Javaid     {
5871fd2a8cfSOmair Javaid         // Update watchpoint in local cache
588ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].address = addr;
589ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].control = control_value;
590ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount = 1;
591ea8c25a8SOmair Javaid 
592ea8c25a8SOmair Javaid         // PTRACE call to set corresponding watchpoint register.
593*3a56363aSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeWATCH);
594*3a56363aSOmair Javaid 
595*3a56363aSOmair Javaid         if (error.Fail())
596*3a56363aSOmair Javaid             return LLDB_INVALID_INDEX32;
597ea8c25a8SOmair Javaid     }
598ea8c25a8SOmair Javaid     else
599ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount++;
600ea8c25a8SOmair Javaid 
601ea8c25a8SOmair Javaid     return wp_index;
602ea8c25a8SOmair Javaid }
603ea8c25a8SOmair Javaid 
604ea8c25a8SOmair Javaid bool
605ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index)
606ea8c25a8SOmair Javaid {
607ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
608ea8c25a8SOmair Javaid 
609ea8c25a8SOmair Javaid     if (log)
610ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
611ea8c25a8SOmair Javaid 
612*3a56363aSOmair Javaid     Error error;
613*3a56363aSOmair Javaid 
6141fd2a8cfSOmair Javaid     // Read hardware breakpoint and watchpoint information.
615*3a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
616*3a56363aSOmair Javaid 
617*3a56363aSOmair Javaid     if (error.Fail())
618*3a56363aSOmair Javaid         return false;
619ea8c25a8SOmair Javaid 
620ea8c25a8SOmair Javaid     if (wp_index >= m_max_hwp_supported)
621ea8c25a8SOmair Javaid         return false;
622ea8c25a8SOmair Javaid 
623ea8c25a8SOmair Javaid     // Update reference count if multiple references.
624ea8c25a8SOmair Javaid     if (m_hwp_regs[wp_index].refcount > 1)
625ea8c25a8SOmair Javaid     {
626ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount--;
627ea8c25a8SOmair Javaid         return true;
628ea8c25a8SOmair Javaid     }
629ea8c25a8SOmair Javaid     else if (m_hwp_regs[wp_index].refcount == 1)
630ea8c25a8SOmair Javaid     {
6311fd2a8cfSOmair Javaid         // Update watchpoint in local cache
632ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].control &= ~1;
633ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].address = 0;
634ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount = 0;
635ea8c25a8SOmair Javaid 
6361fd2a8cfSOmair Javaid         // Ptrace call to update hardware debug registers
637*3a56363aSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeWATCH);
638*3a56363aSOmair Javaid 
639*3a56363aSOmair Javaid         if (error.Fail())
640*3a56363aSOmair Javaid             return false;
641*3a56363aSOmair Javaid 
642ea8c25a8SOmair Javaid         return true;
643ea8c25a8SOmair Javaid     }
644ea8c25a8SOmair Javaid 
645ea8c25a8SOmair Javaid     return false;
646ea8c25a8SOmair Javaid }
647ea8c25a8SOmair Javaid 
648ea8c25a8SOmair Javaid Error
649ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints ()
650ea8c25a8SOmair Javaid {
651ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
652ea8c25a8SOmair Javaid 
653ea8c25a8SOmair Javaid     if (log)
654ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
655ea8c25a8SOmair Javaid 
656*3a56363aSOmair Javaid     Error error;
657*3a56363aSOmair Javaid 
6581fd2a8cfSOmair Javaid     // Read hardware breakpoint and watchpoint information.
659*3a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
660*3a56363aSOmair Javaid 
661*3a56363aSOmair Javaid     if (error.Fail())
662*3a56363aSOmair Javaid         return error;
663ea8c25a8SOmair Javaid 
664ea8c25a8SOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
665ea8c25a8SOmair Javaid     {
666ea8c25a8SOmair Javaid         if (m_hwp_regs[i].control & 0x01)
667ea8c25a8SOmair Javaid         {
6681fd2a8cfSOmair Javaid             // Clear watchpoints in local cache
669ea8c25a8SOmair Javaid             m_hwp_regs[i].control &= ~1;
670ea8c25a8SOmair Javaid             m_hwp_regs[i].address = 0;
671ea8c25a8SOmair Javaid             m_hwp_regs[i].refcount = 0;
672ea8c25a8SOmair Javaid 
6731fd2a8cfSOmair Javaid             // Ptrace call to update hardware debug registers
674*3a56363aSOmair Javaid             error = WriteHardwareDebugRegs(eDREGTypeWATCH);
675*3a56363aSOmair Javaid 
676*3a56363aSOmair Javaid             if (error.Fail())
677*3a56363aSOmair Javaid                 return error;
678ea8c25a8SOmair Javaid         }
679ea8c25a8SOmair Javaid     }
680ea8c25a8SOmair Javaid 
681ea8c25a8SOmair Javaid     return Error();
682ea8c25a8SOmair Javaid }
683ea8c25a8SOmair Javaid 
684ea8c25a8SOmair Javaid uint32_t
685ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index)
686ea8c25a8SOmair Javaid {
687ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
688ea8c25a8SOmair Javaid 
689ea8c25a8SOmair Javaid     if (log)
690ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
691ea8c25a8SOmair Javaid     switch ((m_hwp_regs[wp_index].control >> 5) & 0xff)
692ea8c25a8SOmair Javaid     {
693ea8c25a8SOmair Javaid         case 0x01:
694ea8c25a8SOmair Javaid             return 1;
695ea8c25a8SOmair Javaid         case 0x03:
696ea8c25a8SOmair Javaid             return 2;
697ea8c25a8SOmair Javaid         case 0x0f:
698ea8c25a8SOmair Javaid             return 4;
699ea8c25a8SOmair Javaid         case 0xff:
700ea8c25a8SOmair Javaid             return 8;
701ea8c25a8SOmair Javaid         default:
702ea8c25a8SOmair Javaid             return 0;
703ea8c25a8SOmair Javaid     }
704ea8c25a8SOmair Javaid }
705ea8c25a8SOmair Javaid bool
706ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index)
707ea8c25a8SOmair Javaid {
708ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
709ea8c25a8SOmair Javaid 
710ea8c25a8SOmair Javaid     if (log)
711ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
712ea8c25a8SOmair Javaid 
713ea8c25a8SOmair Javaid     if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
714ea8c25a8SOmair Javaid         return true;
715ea8c25a8SOmair Javaid     else
716ea8c25a8SOmair Javaid         return false;
717ea8c25a8SOmair Javaid }
718ea8c25a8SOmair Javaid 
719ea8c25a8SOmair Javaid Error
720ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
721ea8c25a8SOmair Javaid {
722ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
723ea8c25a8SOmair Javaid 
724ea8c25a8SOmair Javaid     if (log)
725ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
726ea8c25a8SOmair Javaid 
727ea8c25a8SOmair Javaid     uint32_t watch_size;
728ea8c25a8SOmair Javaid     lldb::addr_t watch_addr;
729ea8c25a8SOmair Javaid 
730ea8c25a8SOmair Javaid     for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
731ea8c25a8SOmair Javaid     {
732ea8c25a8SOmair Javaid         watch_size = GetWatchpointSize (wp_index);
733ea8c25a8SOmair Javaid         watch_addr = m_hwp_regs[wp_index].address;
734ea8c25a8SOmair Javaid 
735ea8c25a8SOmair Javaid         if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
736ea8c25a8SOmair Javaid             && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
737ea8c25a8SOmair Javaid         {
738ea8c25a8SOmair Javaid             return Error();
739ea8c25a8SOmair Javaid         }
740ea8c25a8SOmair Javaid     }
741ea8c25a8SOmair Javaid 
742ea8c25a8SOmair Javaid     wp_index = LLDB_INVALID_INDEX32;
743ea8c25a8SOmair Javaid     return Error();
744ea8c25a8SOmair Javaid }
745ea8c25a8SOmair Javaid 
746ea8c25a8SOmair Javaid lldb::addr_t
747ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index)
748ea8c25a8SOmair Javaid {
749ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
750ea8c25a8SOmair Javaid 
751ea8c25a8SOmair Javaid     if (log)
752ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
753ea8c25a8SOmair Javaid 
754ea8c25a8SOmair Javaid     if (wp_index >= m_max_hwp_supported)
755ea8c25a8SOmair Javaid         return LLDB_INVALID_ADDRESS;
756ea8c25a8SOmair Javaid 
757ea8c25a8SOmair Javaid     if (WatchpointIsEnabled(wp_index))
758ea8c25a8SOmair Javaid         return m_hwp_regs[wp_index].address;
759ea8c25a8SOmair Javaid     else
760ea8c25a8SOmair Javaid         return LLDB_INVALID_ADDRESS;
761ea8c25a8SOmair Javaid }
762ea8c25a8SOmair Javaid 
763068f8a7eSTamas Berghammer Error
7641fd2a8cfSOmair Javaid NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo()
765ea8c25a8SOmair Javaid {
7661fd2a8cfSOmair Javaid     if (!m_refresh_hwdebug_info)
7671fd2a8cfSOmair Javaid     {
7681fd2a8cfSOmair Javaid         return Error();
7691fd2a8cfSOmair Javaid     }
7701fd2a8cfSOmair Javaid 
771c7512fdcSPavel Labath     ::pid_t tid = m_thread.GetID();
772ea8c25a8SOmair Javaid 
773c7512fdcSPavel Labath     int regset = NT_ARM_HW_WATCH;
774c7512fdcSPavel Labath     struct iovec ioVec;
775c7512fdcSPavel Labath     struct user_hwdebug_state dreg_state;
776c7512fdcSPavel Labath     Error error;
777c7512fdcSPavel Labath 
778c7512fdcSPavel Labath     ioVec.iov_base = &dreg_state;
779c7512fdcSPavel Labath     ioVec.iov_len = sizeof (dreg_state);
7804a9babb2SPavel Labath     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
781*3a56363aSOmair Javaid 
782*3a56363aSOmair Javaid     if (error.Fail())
783*3a56363aSOmair Javaid         return error;
784*3a56363aSOmair Javaid 
7851fd2a8cfSOmair Javaid     m_max_hwp_supported = dreg_state.dbg_info & 0xff;
786c7512fdcSPavel Labath 
787c7512fdcSPavel Labath     regset = NT_ARM_HW_BREAK;
7884a9babb2SPavel Labath     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
7891fd2a8cfSOmair Javaid 
790*3a56363aSOmair Javaid     if (error.Fail())
791*3a56363aSOmair Javaid         return error;
792*3a56363aSOmair Javaid 
793*3a56363aSOmair Javaid     m_max_hbp_supported = dreg_state.dbg_info & 0xff;
7941fd2a8cfSOmair Javaid     m_refresh_hwdebug_info = false;
795c7512fdcSPavel Labath 
796c7512fdcSPavel Labath     return error;
797ea8c25a8SOmair Javaid }
798068f8a7eSTamas Berghammer 
799068f8a7eSTamas Berghammer Error
8001fd2a8cfSOmair Javaid NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType)
801068f8a7eSTamas Berghammer {
802c7512fdcSPavel Labath     struct iovec ioVec;
803c7512fdcSPavel Labath     struct user_hwdebug_state dreg_state;
804c7512fdcSPavel Labath     Error error;
805c7512fdcSPavel Labath 
806c7512fdcSPavel Labath     memset (&dreg_state, 0, sizeof (dreg_state));
807c7512fdcSPavel Labath     ioVec.iov_base = &dreg_state;
808c7512fdcSPavel Labath     ioVec.iov_len = sizeof (dreg_state);
809c7512fdcSPavel Labath 
8101fd2a8cfSOmair Javaid     if (hwbType == eDREGTypeWATCH)
811c7512fdcSPavel Labath     {
8121fd2a8cfSOmair Javaid         hwbType = NT_ARM_HW_WATCH;
8131fd2a8cfSOmair Javaid 
8141fd2a8cfSOmair Javaid         for (uint32_t i = 0; i < m_max_hwp_supported; i++)
8151fd2a8cfSOmair Javaid         {
8161fd2a8cfSOmair Javaid             dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
8171fd2a8cfSOmair Javaid             dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
8181fd2a8cfSOmair Javaid         }
8191fd2a8cfSOmair Javaid     }
8201fd2a8cfSOmair Javaid     else
8211fd2a8cfSOmair Javaid     {
8221fd2a8cfSOmair Javaid         hwbType = NT_ARM_HW_BREAK;
8231fd2a8cfSOmair Javaid 
8241fd2a8cfSOmair Javaid         for (uint32_t i = 0; i < m_max_hbp_supported; i++)
8251fd2a8cfSOmair Javaid         {
8261fd2a8cfSOmair Javaid             dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address;
8271fd2a8cfSOmair Javaid             dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control;
8281fd2a8cfSOmair Javaid         }
829068f8a7eSTamas Berghammer     }
830068f8a7eSTamas Berghammer 
8311fd2a8cfSOmair Javaid     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &hwbType, &ioVec, ioVec.iov_len);
832c7512fdcSPavel Labath }
833c7512fdcSPavel Labath 
834c7512fdcSPavel Labath Error
835c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset,
836068f8a7eSTamas Berghammer                                                       const char* reg_name,
837068f8a7eSTamas Berghammer                                                       uint32_t size,
838068f8a7eSTamas Berghammer                                                       RegisterValue &value)
839068f8a7eSTamas Berghammer {
840c7512fdcSPavel Labath     Error error;
841c7512fdcSPavel Labath     if (offset > sizeof(struct user_pt_regs))
842c7512fdcSPavel Labath     {
843c7512fdcSPavel Labath         uintptr_t offset = offset - sizeof(struct user_pt_regs);
844c7512fdcSPavel Labath         if (offset > sizeof(struct user_fpsimd_state))
845c7512fdcSPavel Labath         {
846c7512fdcSPavel Labath             error.SetErrorString("invalid offset value");
847c7512fdcSPavel Labath             return error;
848c7512fdcSPavel Labath         }
849c7512fdcSPavel Labath         elf_fpregset_t regs;
850c7512fdcSPavel Labath         int regset = NT_FPREGSET;
851c7512fdcSPavel Labath         struct iovec ioVec;
852c7512fdcSPavel Labath 
853c7512fdcSPavel Labath         ioVec.iov_base = &regs;
854c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
8554a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper(
8564a9babb2SPavel Labath                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
857c7512fdcSPavel Labath         if (error.Success())
858c7512fdcSPavel Labath         {
859c7512fdcSPavel Labath             ArchSpec arch;
860c7512fdcSPavel Labath             if (m_thread.GetProcess()->GetArchitecture(arch))
861c7512fdcSPavel Labath                 value.SetBytes((void *)(((unsigned char *)(&regs)) + offset), 16, arch.GetByteOrder());
862c7512fdcSPavel Labath             else
863c7512fdcSPavel Labath                 error.SetErrorString("failed to get architecture");
864c7512fdcSPavel Labath         }
865c7512fdcSPavel Labath     }
866c7512fdcSPavel Labath     else
867c7512fdcSPavel Labath     {
868c7512fdcSPavel Labath         elf_gregset_t regs;
869c7512fdcSPavel Labath         int regset = NT_PRSTATUS;
870c7512fdcSPavel Labath         struct iovec ioVec;
871c7512fdcSPavel Labath 
872c7512fdcSPavel Labath         ioVec.iov_base = &regs;
873c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
8744a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper(
8754a9babb2SPavel Labath                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
876c7512fdcSPavel Labath         if (error.Success())
877c7512fdcSPavel Labath         {
878c7512fdcSPavel Labath             ArchSpec arch;
879c7512fdcSPavel Labath             if (m_thread.GetProcess()->GetArchitecture(arch))
880c7512fdcSPavel Labath                 value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder());
881c7512fdcSPavel Labath             else
882c7512fdcSPavel Labath                 error.SetErrorString("failed to get architecture");
883c7512fdcSPavel Labath         }
884c7512fdcSPavel Labath     }
885c7512fdcSPavel Labath     return error;
886068f8a7eSTamas Berghammer }
887068f8a7eSTamas Berghammer 
888c7512fdcSPavel Labath Error
889c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset,
890068f8a7eSTamas Berghammer                                                        const char* reg_name,
891068f8a7eSTamas Berghammer                                                        const RegisterValue &value)
892068f8a7eSTamas Berghammer {
893c7512fdcSPavel Labath     Error error;
894c7512fdcSPavel Labath     ::pid_t tid = m_thread.GetID();
895c7512fdcSPavel Labath     if (offset > sizeof(struct user_pt_regs))
896c7512fdcSPavel Labath     {
897c7512fdcSPavel Labath         uintptr_t offset = offset - sizeof(struct user_pt_regs);
898c7512fdcSPavel Labath         if (offset > sizeof(struct user_fpsimd_state))
899c7512fdcSPavel Labath         {
900c7512fdcSPavel Labath             error.SetErrorString("invalid offset value");
901c7512fdcSPavel Labath             return error;
902c7512fdcSPavel Labath         }
903c7512fdcSPavel Labath         elf_fpregset_t regs;
904c7512fdcSPavel Labath         int regset = NT_FPREGSET;
905c7512fdcSPavel Labath         struct iovec ioVec;
906c7512fdcSPavel Labath 
907c7512fdcSPavel Labath         ioVec.iov_base = &regs;
908c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
9094a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
910c7512fdcSPavel Labath 
911c7512fdcSPavel Labath         if (error.Success())
912c7512fdcSPavel Labath         {
913c7512fdcSPavel Labath             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 16);
9144a9babb2SPavel Labath             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
915c7512fdcSPavel Labath         }
916c7512fdcSPavel Labath     }
917c7512fdcSPavel Labath     else
918c7512fdcSPavel Labath     {
919c7512fdcSPavel Labath         elf_gregset_t regs;
920c7512fdcSPavel Labath         int regset = NT_PRSTATUS;
921c7512fdcSPavel Labath         struct iovec ioVec;
922c7512fdcSPavel Labath 
923c7512fdcSPavel Labath         ioVec.iov_base = &regs;
924c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
9254a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
926c7512fdcSPavel Labath         if (error.Success())
927c7512fdcSPavel Labath         {
928c7512fdcSPavel Labath             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 8);
9294a9babb2SPavel Labath             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
930c7512fdcSPavel Labath         }
931c7512fdcSPavel Labath     }
932c7512fdcSPavel Labath     return error;
933068f8a7eSTamas Berghammer }
934068f8a7eSTamas Berghammer 
935c7512fdcSPavel Labath Error
936c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size)
937068f8a7eSTamas Berghammer {
938c7512fdcSPavel Labath     int regset = NT_PRSTATUS;
939c7512fdcSPavel Labath     struct iovec ioVec;
940c7512fdcSPavel Labath     Error error;
941c7512fdcSPavel Labath 
942c7512fdcSPavel Labath     ioVec.iov_base = buf;
943c7512fdcSPavel Labath     ioVec.iov_len = buf_size;
9444a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
945068f8a7eSTamas Berghammer }
946068f8a7eSTamas Berghammer 
947c7512fdcSPavel Labath Error
948c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size)
949068f8a7eSTamas Berghammer {
950c7512fdcSPavel Labath     int regset = NT_PRSTATUS;
951c7512fdcSPavel Labath     struct iovec ioVec;
952c7512fdcSPavel Labath     Error error;
953c7512fdcSPavel Labath 
954c7512fdcSPavel Labath     ioVec.iov_base = buf;
955c7512fdcSPavel Labath     ioVec.iov_len = buf_size;
9564a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
957068f8a7eSTamas Berghammer }
958068f8a7eSTamas Berghammer 
959c7512fdcSPavel Labath Error
960c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size)
961068f8a7eSTamas Berghammer {
962c7512fdcSPavel Labath     int regset = NT_FPREGSET;
963c7512fdcSPavel Labath     struct iovec ioVec;
964c7512fdcSPavel Labath     Error error;
965c7512fdcSPavel Labath 
966c7512fdcSPavel Labath     ioVec.iov_base = buf;
967c7512fdcSPavel Labath     ioVec.iov_len = buf_size;
9684a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
969068f8a7eSTamas Berghammer }
970068f8a7eSTamas Berghammer 
971c7512fdcSPavel Labath Error
972c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size)
973068f8a7eSTamas Berghammer {
974c7512fdcSPavel Labath     int regset = NT_FPREGSET;
975c7512fdcSPavel Labath     struct iovec ioVec;
976c7512fdcSPavel Labath     Error error;
977c7512fdcSPavel Labath 
978c7512fdcSPavel Labath     ioVec.iov_base = buf;
979c7512fdcSPavel Labath     ioVec.iov_len = buf_size;
9804a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
981068f8a7eSTamas Berghammer }
982068f8a7eSTamas Berghammer 
983068f8a7eSTamas Berghammer #endif // defined (__arm64__) || defined (__aarch64__)
984