11e209fccSTamas Berghammer //===-- NativeRegisterContextLinux_arm64.cpp --------------------*- C++ -*-===//
21e209fccSTamas Berghammer //
31e209fccSTamas Berghammer //                     The LLVM Compiler Infrastructure
41e209fccSTamas Berghammer //
51e209fccSTamas Berghammer // This file is distributed under the University of Illinois Open Source
61e209fccSTamas Berghammer // License. See LICENSE.TXT for details.
71e209fccSTamas Berghammer //
81e209fccSTamas Berghammer //===----------------------------------------------------------------------===//
91e209fccSTamas Berghammer 
10068f8a7eSTamas Berghammer #if defined (__arm64__) || defined (__aarch64__)
11068f8a7eSTamas Berghammer 
12e85e6021STamas Berghammer #include "NativeRegisterContextLinux_arm.h"
131e209fccSTamas Berghammer #include "NativeRegisterContextLinux_arm64.h"
141e209fccSTamas Berghammer 
15068f8a7eSTamas Berghammer // C Includes
16068f8a7eSTamas Berghammer // C++ Includes
17068f8a7eSTamas Berghammer 
18068f8a7eSTamas Berghammer // Other libraries and framework includes
191e209fccSTamas Berghammer #include "lldb/Core/DataBufferHeap.h"
201e209fccSTamas Berghammer #include "lldb/Core/Error.h"
21068f8a7eSTamas Berghammer #include "lldb/Core/Log.h"
221e209fccSTamas Berghammer #include "lldb/Core/RegisterValue.h"
231e209fccSTamas Berghammer #include "lldb/Host/common/NativeProcessProtocol.h"
241e209fccSTamas Berghammer 
25068f8a7eSTamas Berghammer #include "Plugins/Process/Linux/NativeProcessLinux.h"
26068f8a7eSTamas Berghammer #include "Plugins/Process/Linux/Procfs.h"
27e85e6021STamas Berghammer #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
28068f8a7eSTamas Berghammer #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
29068f8a7eSTamas Berghammer 
30068f8a7eSTamas Berghammer // System includes - They have to be included after framework includes because they define some
31068f8a7eSTamas Berghammer // macros which collide with variable names in other modules
32068f8a7eSTamas Berghammer #include <sys/socket.h>
33068f8a7eSTamas Berghammer // NT_PRSTATUS and NT_FPREGSET definition
34068f8a7eSTamas Berghammer #include <elf.h>
35dd4799c2SSaleem Abdulrasool // user_hwdebug_state definition
36dd4799c2SSaleem Abdulrasool #include <asm/ptrace.h>
37068f8a7eSTamas Berghammer 
38068f8a7eSTamas Berghammer #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
391e209fccSTamas Berghammer 
401e209fccSTamas Berghammer using namespace lldb;
411e209fccSTamas Berghammer using namespace lldb_private;
42db264a6dSTamas Berghammer using namespace lldb_private::process_linux;
431e209fccSTamas Berghammer 
441e209fccSTamas Berghammer // ARM64 general purpose registers.
451e209fccSTamas Berghammer static const uint32_t g_gpr_regnums_arm64[] =
461e209fccSTamas Berghammer {
471e209fccSTamas Berghammer     gpr_x0_arm64,
481e209fccSTamas Berghammer     gpr_x1_arm64,
491e209fccSTamas Berghammer     gpr_x2_arm64,
501e209fccSTamas Berghammer     gpr_x3_arm64,
511e209fccSTamas Berghammer     gpr_x4_arm64,
521e209fccSTamas Berghammer     gpr_x5_arm64,
531e209fccSTamas Berghammer     gpr_x6_arm64,
541e209fccSTamas Berghammer     gpr_x7_arm64,
551e209fccSTamas Berghammer     gpr_x8_arm64,
561e209fccSTamas Berghammer     gpr_x9_arm64,
571e209fccSTamas Berghammer     gpr_x10_arm64,
581e209fccSTamas Berghammer     gpr_x11_arm64,
591e209fccSTamas Berghammer     gpr_x12_arm64,
601e209fccSTamas Berghammer     gpr_x13_arm64,
611e209fccSTamas Berghammer     gpr_x14_arm64,
621e209fccSTamas Berghammer     gpr_x15_arm64,
631e209fccSTamas Berghammer     gpr_x16_arm64,
641e209fccSTamas Berghammer     gpr_x17_arm64,
651e209fccSTamas Berghammer     gpr_x18_arm64,
661e209fccSTamas Berghammer     gpr_x19_arm64,
671e209fccSTamas Berghammer     gpr_x20_arm64,
681e209fccSTamas Berghammer     gpr_x21_arm64,
691e209fccSTamas Berghammer     gpr_x22_arm64,
701e209fccSTamas Berghammer     gpr_x23_arm64,
711e209fccSTamas Berghammer     gpr_x24_arm64,
721e209fccSTamas Berghammer     gpr_x25_arm64,
731e209fccSTamas Berghammer     gpr_x26_arm64,
741e209fccSTamas Berghammer     gpr_x27_arm64,
751e209fccSTamas Berghammer     gpr_x28_arm64,
761e209fccSTamas Berghammer     gpr_fp_arm64,
771e209fccSTamas Berghammer     gpr_lr_arm64,
781e209fccSTamas Berghammer     gpr_sp_arm64,
791e209fccSTamas Berghammer     gpr_pc_arm64,
801e209fccSTamas Berghammer     gpr_cpsr_arm64,
811e209fccSTamas Berghammer     LLDB_INVALID_REGNUM // register sets need to end with this flag
821e209fccSTamas Berghammer };
831e209fccSTamas Berghammer static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \
841e209fccSTamas Berghammer               "g_gpr_regnums_arm64 has wrong number of register infos");
851e209fccSTamas Berghammer 
861e209fccSTamas Berghammer // ARM64 floating point registers.
871e209fccSTamas Berghammer static const uint32_t g_fpu_regnums_arm64[] =
881e209fccSTamas Berghammer {
891e209fccSTamas Berghammer     fpu_v0_arm64,
901e209fccSTamas Berghammer     fpu_v1_arm64,
911e209fccSTamas Berghammer     fpu_v2_arm64,
921e209fccSTamas Berghammer     fpu_v3_arm64,
931e209fccSTamas Berghammer     fpu_v4_arm64,
941e209fccSTamas Berghammer     fpu_v5_arm64,
951e209fccSTamas Berghammer     fpu_v6_arm64,
961e209fccSTamas Berghammer     fpu_v7_arm64,
971e209fccSTamas Berghammer     fpu_v8_arm64,
981e209fccSTamas Berghammer     fpu_v9_arm64,
991e209fccSTamas Berghammer     fpu_v10_arm64,
1001e209fccSTamas Berghammer     fpu_v11_arm64,
1011e209fccSTamas Berghammer     fpu_v12_arm64,
1021e209fccSTamas Berghammer     fpu_v13_arm64,
1031e209fccSTamas Berghammer     fpu_v14_arm64,
1041e209fccSTamas Berghammer     fpu_v15_arm64,
1051e209fccSTamas Berghammer     fpu_v16_arm64,
1061e209fccSTamas Berghammer     fpu_v17_arm64,
1071e209fccSTamas Berghammer     fpu_v18_arm64,
1081e209fccSTamas Berghammer     fpu_v19_arm64,
1091e209fccSTamas Berghammer     fpu_v20_arm64,
1101e209fccSTamas Berghammer     fpu_v21_arm64,
1111e209fccSTamas Berghammer     fpu_v22_arm64,
1121e209fccSTamas Berghammer     fpu_v23_arm64,
1131e209fccSTamas Berghammer     fpu_v24_arm64,
1141e209fccSTamas Berghammer     fpu_v25_arm64,
1151e209fccSTamas Berghammer     fpu_v26_arm64,
1161e209fccSTamas Berghammer     fpu_v27_arm64,
1171e209fccSTamas Berghammer     fpu_v28_arm64,
1181e209fccSTamas Berghammer     fpu_v29_arm64,
1191e209fccSTamas Berghammer     fpu_v30_arm64,
1201e209fccSTamas Berghammer     fpu_v31_arm64,
1211e209fccSTamas Berghammer     fpu_fpsr_arm64,
1221e209fccSTamas Berghammer     fpu_fpcr_arm64,
1231e209fccSTamas Berghammer     LLDB_INVALID_REGNUM // register sets need to end with this flag
1241e209fccSTamas Berghammer };
1251e209fccSTamas Berghammer static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \
1261e209fccSTamas Berghammer               "g_fpu_regnums_arm64 has wrong number of register infos");
1271e209fccSTamas Berghammer 
1281e209fccSTamas Berghammer namespace {
1291e209fccSTamas Berghammer     // Number of register sets provided by this context.
1301e209fccSTamas Berghammer     enum
1311e209fccSTamas Berghammer     {
1321e209fccSTamas Berghammer         k_num_register_sets = 2
1331e209fccSTamas Berghammer     };
1341e209fccSTamas Berghammer }
1351e209fccSTamas Berghammer 
1361e209fccSTamas Berghammer // Register sets for ARM64.
137db264a6dSTamas Berghammer static const RegisterSet
1381e209fccSTamas Berghammer g_reg_sets_arm64[k_num_register_sets] =
1391e209fccSTamas Berghammer {
1401e209fccSTamas Berghammer     { "General Purpose Registers",  "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 },
1411e209fccSTamas Berghammer     { "Floating Point Registers",   "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 }
1421e209fccSTamas Berghammer };
1431e209fccSTamas Berghammer 
144068f8a7eSTamas Berghammer NativeRegisterContextLinux*
145068f8a7eSTamas Berghammer NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
146068f8a7eSTamas Berghammer                                                                  NativeThreadProtocol &native_thread,
147068f8a7eSTamas Berghammer                                                                  uint32_t concrete_frame_idx)
148068f8a7eSTamas Berghammer {
149e85e6021STamas Berghammer     Log *log  = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS);
150e85e6021STamas Berghammer     switch (target_arch.GetMachine())
151e85e6021STamas Berghammer     {
152e85e6021STamas Berghammer         case llvm::Triple::arm:
153e85e6021STamas Berghammer             return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx);
154e85e6021STamas Berghammer         case llvm::Triple::aarch64:
155068f8a7eSTamas Berghammer             return new NativeRegisterContextLinux_arm64(target_arch, native_thread, concrete_frame_idx);
156e85e6021STamas Berghammer         default:
157e85e6021STamas Berghammer             if (log)
158e85e6021STamas Berghammer                 log->Printf("NativeRegisterContextLinux::%s() have no register context for architecture: %s\n", __FUNCTION__,
159e85e6021STamas Berghammer                             target_arch.GetTriple().getArchName().str().c_str());
160e85e6021STamas Berghammer             return nullptr;
161e85e6021STamas Berghammer     }
162068f8a7eSTamas Berghammer }
163068f8a7eSTamas Berghammer 
164068f8a7eSTamas Berghammer NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (const ArchSpec& target_arch,
165068f8a7eSTamas Berghammer                                                                     NativeThreadProtocol &native_thread,
166068f8a7eSTamas Berghammer                                                                     uint32_t concrete_frame_idx) :
167068f8a7eSTamas Berghammer     NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm64(target_arch))
168068f8a7eSTamas Berghammer {
169068f8a7eSTamas Berghammer     switch (target_arch.GetMachine())
1701e209fccSTamas Berghammer     {
1711e209fccSTamas Berghammer         case llvm::Triple::aarch64:
1721e209fccSTamas Berghammer             m_reg_info.num_registers     = k_num_registers_arm64;
1731e209fccSTamas Berghammer             m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64;
1741e209fccSTamas Berghammer             m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64;
1751e209fccSTamas Berghammer             m_reg_info.last_gpr          = k_last_gpr_arm64;
1761e209fccSTamas Berghammer             m_reg_info.first_fpr         = k_first_fpr_arm64;
1771e209fccSTamas Berghammer             m_reg_info.last_fpr          = k_last_fpr_arm64;
1781e209fccSTamas Berghammer             m_reg_info.first_fpr_v       = fpu_v0_arm64;
1791e209fccSTamas Berghammer             m_reg_info.last_fpr_v        = fpu_v31_arm64;
1801e209fccSTamas Berghammer             m_reg_info.gpr_flags         = gpr_cpsr_arm64;
1811e209fccSTamas Berghammer             break;
1821e209fccSTamas Berghammer         default:
1831e209fccSTamas Berghammer             assert(false && "Unhandled target architecture.");
1841e209fccSTamas Berghammer             break;
1851e209fccSTamas Berghammer     }
1861e209fccSTamas Berghammer 
1871e209fccSTamas Berghammer     ::memset(&m_fpr, 0, sizeof (m_fpr));
1881e209fccSTamas Berghammer     ::memset(&m_gpr_arm64, 0, sizeof (m_gpr_arm64));
189ea8c25a8SOmair Javaid     ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs));
190ea8c25a8SOmair Javaid 
191ea8c25a8SOmair Javaid     // 16 is just a maximum value, query hardware for actual watchpoint count
192ea8c25a8SOmair Javaid     m_max_hwp_supported = 16;
193ea8c25a8SOmair Javaid     m_max_hbp_supported = 16;
194ea8c25a8SOmair Javaid     m_refresh_hwdebug_info = true;
1951e209fccSTamas Berghammer }
1961e209fccSTamas Berghammer 
1971e209fccSTamas Berghammer uint32_t
1981e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetRegisterSetCount () const
1991e209fccSTamas Berghammer {
2001e209fccSTamas Berghammer     return k_num_register_sets;
2011e209fccSTamas Berghammer }
2021e209fccSTamas Berghammer 
203db264a6dSTamas Berghammer const RegisterSet *
2041e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetRegisterSet (uint32_t set_index) const
2051e209fccSTamas Berghammer {
2061e209fccSTamas Berghammer     if (set_index < k_num_register_sets)
2071e209fccSTamas Berghammer         return &g_reg_sets_arm64[set_index];
2081e209fccSTamas Berghammer 
2091e209fccSTamas Berghammer     return nullptr;
2101e209fccSTamas Berghammer }
2111e209fccSTamas Berghammer 
212cec93c35STamas Berghammer uint32_t
213cec93c35STamas Berghammer NativeRegisterContextLinux_arm64::GetUserRegisterCount() const
214cec93c35STamas Berghammer {
215cec93c35STamas Berghammer     uint32_t count = 0;
216cec93c35STamas Berghammer     for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
217cec93c35STamas Berghammer         count += g_reg_sets_arm64[set_index].num_registers;
218cec93c35STamas Berghammer     return count;
219cec93c35STamas Berghammer }
220cec93c35STamas Berghammer 
221db264a6dSTamas Berghammer Error
2221e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
2231e209fccSTamas Berghammer {
2241e209fccSTamas Berghammer     Error error;
2251e209fccSTamas Berghammer 
2261e209fccSTamas Berghammer     if (!reg_info)
2271e209fccSTamas Berghammer     {
2281e209fccSTamas Berghammer         error.SetErrorString ("reg_info NULL");
2291e209fccSTamas Berghammer         return error;
2301e209fccSTamas Berghammer     }
2311e209fccSTamas Berghammer 
2321e209fccSTamas Berghammer     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
2331e209fccSTamas Berghammer 
2341e209fccSTamas Berghammer     if (IsFPR(reg))
2351e209fccSTamas Berghammer     {
236068f8a7eSTamas Berghammer         error = ReadFPR();
237068f8a7eSTamas Berghammer         if (error.Fail())
2381e209fccSTamas Berghammer             return error;
2391e209fccSTamas Berghammer     }
2401e209fccSTamas Berghammer     else
2411e209fccSTamas Berghammer     {
2421e209fccSTamas Berghammer         uint32_t full_reg = reg;
2431e209fccSTamas Berghammer         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
2441e209fccSTamas Berghammer 
2451e209fccSTamas Berghammer         if (is_subreg)
2461e209fccSTamas Berghammer         {
2471e209fccSTamas Berghammer             // Read the full aligned 64-bit register.
2481e209fccSTamas Berghammer             full_reg = reg_info->invalidate_regs[0];
2491e209fccSTamas Berghammer         }
2501e209fccSTamas Berghammer 
2511e209fccSTamas Berghammer         error = ReadRegisterRaw(full_reg, reg_value);
2521e209fccSTamas Berghammer 
2531e209fccSTamas Berghammer         if (error.Success ())
2541e209fccSTamas Berghammer         {
2551e209fccSTamas Berghammer             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
2561e209fccSTamas Berghammer             if (is_subreg && (reg_info->byte_offset & 0x1))
2571e209fccSTamas Berghammer                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
2581e209fccSTamas Berghammer 
2591e209fccSTamas Berghammer             // If our return byte size was greater than the return value reg size, then
2601e209fccSTamas Berghammer             // use the type specified by reg_info rather than the uint64_t default
2611e209fccSTamas Berghammer             if (reg_value.GetByteSize() > reg_info->byte_size)
2621e209fccSTamas Berghammer                 reg_value.SetType(reg_info);
2631e209fccSTamas Berghammer         }
2641e209fccSTamas Berghammer         return error;
2651e209fccSTamas Berghammer     }
2661e209fccSTamas Berghammer 
2671e209fccSTamas Berghammer     // Get pointer to m_fpr variable and set the data from it.
268c40e7b17STamas Berghammer     uint32_t fpr_offset = CalculateFprOffset(reg_info);
269c40e7b17STamas Berghammer     assert (fpr_offset < sizeof m_fpr);
270c40e7b17STamas Berghammer     uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
271cec93c35STamas Berghammer     reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, eByteOrderLittle, error);
2721e209fccSTamas Berghammer 
2731e209fccSTamas Berghammer     return error;
2741e209fccSTamas Berghammer }
2751e209fccSTamas Berghammer 
276db264a6dSTamas Berghammer Error
2771e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
2781e209fccSTamas Berghammer {
2791e209fccSTamas Berghammer     if (!reg_info)
2801e209fccSTamas Berghammer         return Error ("reg_info NULL");
2811e209fccSTamas Berghammer 
2821e209fccSTamas Berghammer     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
2831e209fccSTamas Berghammer     if (reg_index == LLDB_INVALID_REGNUM)
2841e209fccSTamas Berghammer         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
2851e209fccSTamas Berghammer 
2861e209fccSTamas Berghammer     if (IsGPR(reg_index))
2871e209fccSTamas Berghammer         return WriteRegisterRaw(reg_index, reg_value);
2881e209fccSTamas Berghammer 
2891e209fccSTamas Berghammer     if (IsFPR(reg_index))
2901e209fccSTamas Berghammer     {
2911e209fccSTamas Berghammer         // Get pointer to m_fpr variable and set the data to it.
292c40e7b17STamas Berghammer         uint32_t fpr_offset = CalculateFprOffset(reg_info);
293c40e7b17STamas Berghammer         assert (fpr_offset < sizeof m_fpr);
294c40e7b17STamas Berghammer         uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
2951e209fccSTamas Berghammer         switch (reg_info->byte_size)
2961e209fccSTamas Berghammer         {
2971e209fccSTamas Berghammer             case 2:
2981e209fccSTamas Berghammer                 *(uint16_t *)dst = reg_value.GetAsUInt16();
2991e209fccSTamas Berghammer                 break;
3001e209fccSTamas Berghammer             case 4:
3011e209fccSTamas Berghammer                 *(uint32_t *)dst = reg_value.GetAsUInt32();
3021e209fccSTamas Berghammer                 break;
3031e209fccSTamas Berghammer             case 8:
3041e209fccSTamas Berghammer                 *(uint64_t *)dst = reg_value.GetAsUInt64();
3051e209fccSTamas Berghammer                 break;
3061e209fccSTamas Berghammer             default:
3071e209fccSTamas Berghammer                 assert(false && "Unhandled data size.");
3081e209fccSTamas Berghammer                 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
3091e209fccSTamas Berghammer         }
3101e209fccSTamas Berghammer 
311068f8a7eSTamas Berghammer         Error error = WriteFPR();
312068f8a7eSTamas Berghammer         if (error.Fail())
313068f8a7eSTamas Berghammer             return error;
3141e209fccSTamas Berghammer 
3151e209fccSTamas Berghammer         return Error ();
3161e209fccSTamas Berghammer     }
3171e209fccSTamas Berghammer 
3181e209fccSTamas Berghammer     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
3191e209fccSTamas Berghammer }
3201e209fccSTamas Berghammer 
321db264a6dSTamas Berghammer Error
3221e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
3231e209fccSTamas Berghammer {
3241e209fccSTamas Berghammer     Error error;
3251e209fccSTamas Berghammer 
326db264a6dSTamas Berghammer     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
3271e209fccSTamas Berghammer     if (!data_sp)
3281e209fccSTamas Berghammer         return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
3291e209fccSTamas Berghammer 
330068f8a7eSTamas Berghammer     error = ReadGPR();
331068f8a7eSTamas Berghammer     if (error.Fail())
3321e209fccSTamas Berghammer         return error;
3331e209fccSTamas Berghammer 
334068f8a7eSTamas Berghammer     error = ReadFPR();
335068f8a7eSTamas Berghammer     if (error.Fail())
3361e209fccSTamas Berghammer         return error;
3371e209fccSTamas Berghammer 
3381e209fccSTamas Berghammer     uint8_t *dst = data_sp->GetBytes ();
3391e209fccSTamas Berghammer     if (dst == nullptr)
3401e209fccSTamas Berghammer     {
3411e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
3421e209fccSTamas Berghammer         return error;
3431e209fccSTamas Berghammer     }
3441e209fccSTamas Berghammer 
3451e209fccSTamas Berghammer     ::memcpy (dst, &m_gpr_arm64, GetGPRSize());
3461e209fccSTamas Berghammer     dst += GetGPRSize();
3471e209fccSTamas Berghammer     ::memcpy (dst, &m_fpr, sizeof(m_fpr));
3481e209fccSTamas Berghammer 
3491e209fccSTamas Berghammer     return error;
3501e209fccSTamas Berghammer }
3511e209fccSTamas Berghammer 
352db264a6dSTamas Berghammer Error
3531e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
3541e209fccSTamas Berghammer {
3551e209fccSTamas Berghammer     Error error;
3561e209fccSTamas Berghammer 
3571e209fccSTamas Berghammer     if (!data_sp)
3581e209fccSTamas Berghammer     {
3591e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
3601e209fccSTamas Berghammer         return error;
3611e209fccSTamas Berghammer     }
3621e209fccSTamas Berghammer 
3631e209fccSTamas Berghammer     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
3641e209fccSTamas Berghammer     {
3651e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
3661e209fccSTamas Berghammer         return error;
3671e209fccSTamas Berghammer     }
3681e209fccSTamas Berghammer 
3691e209fccSTamas Berghammer 
3701e209fccSTamas Berghammer     uint8_t *src = data_sp->GetBytes ();
3711e209fccSTamas Berghammer     if (src == nullptr)
3721e209fccSTamas Berghammer     {
3731e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
3741e209fccSTamas Berghammer         return error;
3751e209fccSTamas Berghammer     }
3761e209fccSTamas Berghammer     ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ());
3771e209fccSTamas Berghammer 
378068f8a7eSTamas Berghammer     error = WriteGPR();
379068f8a7eSTamas Berghammer     if (error.Fail())
3801e209fccSTamas Berghammer         return error;
3811e209fccSTamas Berghammer 
3821e209fccSTamas Berghammer     src += GetRegisterInfoInterface ().GetGPRSize ();
3831e209fccSTamas Berghammer     ::memcpy (&m_fpr, src, sizeof(m_fpr));
3841e209fccSTamas Berghammer 
385068f8a7eSTamas Berghammer     error = WriteFPR();
3861e209fccSTamas Berghammer     if (error.Fail())
3871e209fccSTamas Berghammer         return error;
3881e209fccSTamas Berghammer 
3891e209fccSTamas Berghammer     return error;
3901e209fccSTamas Berghammer }
3911e209fccSTamas Berghammer 
3921e209fccSTamas Berghammer bool
3931e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const
3941e209fccSTamas Berghammer {
3951e209fccSTamas Berghammer     return reg <= m_reg_info.last_gpr;   // GPR's come first.
3961e209fccSTamas Berghammer }
3971e209fccSTamas Berghammer 
3981e209fccSTamas Berghammer bool
3991e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const
4001e209fccSTamas Berghammer {
4011e209fccSTamas Berghammer     return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
4021e209fccSTamas Berghammer }
4031e209fccSTamas Berghammer 
404ea8c25a8SOmair Javaid uint32_t
405ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
406ea8c25a8SOmair Javaid {
407ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
408ea8c25a8SOmair Javaid 
409ea8c25a8SOmair Javaid     if (log)
410ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
411ea8c25a8SOmair Javaid 
4123a56363aSOmair Javaid     Error error;
413ea8c25a8SOmair Javaid 
4143a56363aSOmair Javaid     // Read hardware breakpoint and watchpoint information.
4153a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
4163a56363aSOmair Javaid 
4173a56363aSOmair Javaid     if (error.Fail())
4183a56363aSOmair Javaid         return LLDB_INVALID_INDEX32;
4193a56363aSOmair Javaid 
4203a56363aSOmair Javaid     uint32_t control_value = 0, bp_index = 0;
421ea8c25a8SOmair Javaid 
422ea8c25a8SOmair Javaid     // Check if size has a valid hardware breakpoint length.
423ea8c25a8SOmair Javaid     if (size != 4)
424ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32;  // Invalid size for a AArch64 hardware breakpoint
425ea8c25a8SOmair Javaid 
426ea8c25a8SOmair Javaid     // Check 4-byte alignment for hardware breakpoint target address.
427ea8c25a8SOmair Javaid     if (addr & 0x03)
428ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
429ea8c25a8SOmair Javaid 
430ea8c25a8SOmair Javaid     // Setup control value
431ea8c25a8SOmair Javaid     control_value = 0;
432ea8c25a8SOmair Javaid     control_value |= ((1 << size) - 1) << 5;
433ea8c25a8SOmair Javaid     control_value |= (2 << 1) | 1;
434ea8c25a8SOmair Javaid 
435ea8c25a8SOmair Javaid     // Iterate over stored hardware breakpoints
436ea8c25a8SOmair Javaid     // Find a free bp_index or update reference count if duplicate.
437ea8c25a8SOmair Javaid     bp_index = LLDB_INVALID_INDEX32;
438ea8c25a8SOmair Javaid     for (uint32_t i = 0; i < m_max_hbp_supported; i++)
439ea8c25a8SOmair Javaid     {
440ea8c25a8SOmair Javaid         if ((m_hbr_regs[i].control & 1) == 0)
441ea8c25a8SOmair Javaid         {
442ea8c25a8SOmair Javaid             bp_index = i;  // Mark last free slot
443ea8c25a8SOmair Javaid         }
444ea8c25a8SOmair Javaid         else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
445ea8c25a8SOmair Javaid         {
446ea8c25a8SOmair Javaid             bp_index = i;  // Mark duplicate index
447ea8c25a8SOmair Javaid             break;  // Stop searching here
448ea8c25a8SOmair Javaid         }
449ea8c25a8SOmair Javaid     }
450ea8c25a8SOmair Javaid 
451ea8c25a8SOmair Javaid      if (bp_index == LLDB_INVALID_INDEX32)
452ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32;
453ea8c25a8SOmair Javaid 
454f24741d9SOmair Javaid     // Add new or update existing breakpoint
455ea8c25a8SOmair Javaid     if ((m_hbr_regs[bp_index].control & 1) == 0)
456ea8c25a8SOmair Javaid     {
457ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].address = addr;
458ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].control = control_value;
459ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].refcount = 1;
460ea8c25a8SOmair Javaid 
4611fd2a8cfSOmair Javaid         // PTRACE call to set corresponding hardware breakpoint register.
4623a56363aSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeBREAK);
4633a56363aSOmair Javaid 
4643a56363aSOmair Javaid         if (error.Fail())
465f24741d9SOmair Javaid         {
466f24741d9SOmair Javaid             m_hbr_regs[bp_index].address = 0;
467f24741d9SOmair Javaid             m_hbr_regs[bp_index].control &= ~1;
468f24741d9SOmair Javaid             m_hbr_regs[bp_index].refcount = 0;
469f24741d9SOmair Javaid 
4703a56363aSOmair Javaid             return LLDB_INVALID_INDEX32;
471ea8c25a8SOmair Javaid         }
472f24741d9SOmair Javaid     }
473ea8c25a8SOmair Javaid     else
474ea8c25a8SOmair Javaid         m_hbr_regs[bp_index].refcount++;
475ea8c25a8SOmair Javaid 
476ea8c25a8SOmair Javaid     return bp_index;
477ea8c25a8SOmair Javaid }
478ea8c25a8SOmair Javaid 
479ea8c25a8SOmair Javaid bool
480ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx)
481ea8c25a8SOmair Javaid {
482ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
483ea8c25a8SOmair Javaid 
484ea8c25a8SOmair Javaid     if (log)
485ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
486ea8c25a8SOmair Javaid 
4873a56363aSOmair Javaid     Error error;
4883a56363aSOmair Javaid 
4891fd2a8cfSOmair Javaid     // Read hardware breakpoint and watchpoint information.
4903a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
4913a56363aSOmair Javaid 
4923a56363aSOmair Javaid     if (error.Fail())
4933a56363aSOmair Javaid         return false;
4941fd2a8cfSOmair Javaid 
495ea8c25a8SOmair Javaid     if (hw_idx >= m_max_hbp_supported)
496ea8c25a8SOmair Javaid         return false;
497ea8c25a8SOmair Javaid 
498ea8c25a8SOmair Javaid     // Update reference count if multiple references.
499ea8c25a8SOmair Javaid     if (m_hbr_regs[hw_idx].refcount > 1)
500ea8c25a8SOmair Javaid     {
501ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].refcount--;
502ea8c25a8SOmair Javaid         return true;
503ea8c25a8SOmair Javaid     }
504ea8c25a8SOmair Javaid     else if (m_hbr_regs[hw_idx].refcount == 1)
505ea8c25a8SOmair Javaid     {
506f24741d9SOmair Javaid         // Create a backup we can revert to in case of failure.
507f24741d9SOmair Javaid         lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
508f24741d9SOmair Javaid         uint32_t tempControl = m_hbr_regs[hw_idx].control;
509f24741d9SOmair Javaid         uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount;
510f24741d9SOmair Javaid 
511ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].control &= ~1;
512ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].address = 0;
513ea8c25a8SOmair Javaid         m_hbr_regs[hw_idx].refcount = 0;
514ea8c25a8SOmair Javaid 
5151fd2a8cfSOmair Javaid         // PTRACE call to clear corresponding hardware breakpoint register.
5161fd2a8cfSOmair Javaid         WriteHardwareDebugRegs(eDREGTypeBREAK);
5173a56363aSOmair Javaid 
5183a56363aSOmair Javaid         if (error.Fail())
519f24741d9SOmair Javaid         {
520f24741d9SOmair Javaid             m_hbr_regs[hw_idx].control = tempControl;
521f24741d9SOmair Javaid             m_hbr_regs[hw_idx].address = tempAddr;
522f24741d9SOmair Javaid             m_hbr_regs[hw_idx].refcount = tempRefCount;
523f24741d9SOmair Javaid 
5243a56363aSOmair Javaid             return false;
525f24741d9SOmair Javaid         }
5263a56363aSOmair Javaid 
5273a56363aSOmair Javaid         return true;
528ea8c25a8SOmair Javaid     }
529ea8c25a8SOmair Javaid 
530ea8c25a8SOmair Javaid     return false;
531ea8c25a8SOmair Javaid }
532ea8c25a8SOmair Javaid 
533ea8c25a8SOmair Javaid uint32_t
534ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints ()
535ea8c25a8SOmair Javaid {
536ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
537ea8c25a8SOmair Javaid 
538ea8c25a8SOmair Javaid     if (log)
539ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
540ea8c25a8SOmair Javaid 
5413a56363aSOmair Javaid     Error error;
5423a56363aSOmair Javaid 
5431fd2a8cfSOmair Javaid     // Read hardware breakpoint and watchpoint information.
5443a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
5453a56363aSOmair Javaid 
5463a56363aSOmair Javaid     if (error.Fail())
5473a56363aSOmair Javaid         return LLDB_INVALID_INDEX32;
5481fd2a8cfSOmair Javaid 
549ea8c25a8SOmair Javaid     return m_max_hwp_supported;
550ea8c25a8SOmair Javaid }
551ea8c25a8SOmair Javaid 
552ea8c25a8SOmair Javaid uint32_t
553ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
554ea8c25a8SOmair Javaid {
555ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
556ea8c25a8SOmair Javaid 
557ea8c25a8SOmair Javaid     if (log)
558ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
559ea8c25a8SOmair Javaid 
5603a56363aSOmair Javaid     Error error;
561ea8c25a8SOmair Javaid 
5623a56363aSOmair Javaid     // Read hardware breakpoint and watchpoint information.
5633a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
5643a56363aSOmair Javaid 
5653a56363aSOmair Javaid     if (error.Fail())
5663a56363aSOmair Javaid         return LLDB_INVALID_INDEX32;
5673a56363aSOmair Javaid 
5683a56363aSOmair Javaid     uint32_t control_value = 0, wp_index = 0;
569*43507f57SOmair Javaid     lldb::addr_t real_addr = addr;
570ea8c25a8SOmair Javaid 
5711fd2a8cfSOmair Javaid     // Check if we are setting watchpoint other than read/write/access
5721fd2a8cfSOmair Javaid     // Also update watchpoint flag to match AArch64 write-read bit configuration.
5731fd2a8cfSOmair Javaid     switch (watch_flags)
5741fd2a8cfSOmair Javaid     {
5751fd2a8cfSOmair Javaid         case 1:
5761fd2a8cfSOmair Javaid             watch_flags = 2;
5771fd2a8cfSOmair Javaid             break;
5781fd2a8cfSOmair Javaid         case 2:
5791fd2a8cfSOmair Javaid             watch_flags = 1;
5801fd2a8cfSOmair Javaid             break;
5811fd2a8cfSOmair Javaid         case 3:
5821fd2a8cfSOmair Javaid             break;
5831fd2a8cfSOmair Javaid         default:
5841fd2a8cfSOmair Javaid             return LLDB_INVALID_INDEX32;
5851fd2a8cfSOmair Javaid     }
586ea8c25a8SOmair Javaid 
587ea8c25a8SOmair Javaid     // Check if size has a valid hardware watchpoint length.
588ea8c25a8SOmair Javaid     if (size != 1 && size != 2 && size != 4 && size != 8)
5891fd2a8cfSOmair Javaid         return LLDB_INVALID_INDEX32;
590ea8c25a8SOmair Javaid 
591ea8c25a8SOmair Javaid     // Check 8-byte alignment for hardware watchpoint target address.
592*43507f57SOmair Javaid     // Below is a hack to recalculate address and size in order to
593*43507f57SOmair Javaid     // make sure we can watch non 8-byte alligned addresses as well.
594ea8c25a8SOmair Javaid     if (addr & 0x07)
595*43507f57SOmair Javaid     {
596*43507f57SOmair Javaid         uint8_t watch_mask = (addr & 0x07) + size;
597*43507f57SOmair Javaid 
598*43507f57SOmair Javaid         if (watch_mask > 0x08)
5991fd2a8cfSOmair Javaid             return LLDB_INVALID_INDEX32;
600*43507f57SOmair Javaid         else if (watch_mask <= 0x02)
601*43507f57SOmair Javaid             size = 2;
602*43507f57SOmair Javaid         else if (watch_mask <= 0x04)
603*43507f57SOmair Javaid             size = 4;
604*43507f57SOmair Javaid         else
605*43507f57SOmair Javaid             size = 8;
606*43507f57SOmair Javaid 
607*43507f57SOmair Javaid         addr = addr & (~0x07);
608*43507f57SOmair Javaid     }
609ea8c25a8SOmair Javaid 
610ea8c25a8SOmair Javaid     // Setup control value
611ea8c25a8SOmair Javaid     control_value = watch_flags << 3;
612ea8c25a8SOmair Javaid     control_value |= ((1 << size) - 1) << 5;
613ea8c25a8SOmair Javaid     control_value |= (2 << 1) | 1;
614ea8c25a8SOmair Javaid 
615ea8c25a8SOmair Javaid     // Iterate over stored watchpoints
616ea8c25a8SOmair Javaid     // Find a free wp_index or update reference count if duplicate.
617ea8c25a8SOmair Javaid     wp_index = LLDB_INVALID_INDEX32;
618ea8c25a8SOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
619ea8c25a8SOmair Javaid     {
620ea8c25a8SOmair Javaid         if ((m_hwp_regs[i].control & 1) == 0)
621ea8c25a8SOmair Javaid         {
622ea8c25a8SOmair Javaid             wp_index = i; // Mark last free slot
623ea8c25a8SOmair Javaid         }
624ea8c25a8SOmair Javaid         else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
625ea8c25a8SOmair Javaid         {
626ea8c25a8SOmair Javaid             wp_index = i; // Mark duplicate index
627ea8c25a8SOmair Javaid             break; // Stop searching here
628ea8c25a8SOmair Javaid         }
629ea8c25a8SOmair Javaid     }
630ea8c25a8SOmair Javaid 
631ea8c25a8SOmair Javaid      if (wp_index == LLDB_INVALID_INDEX32)
632ea8c25a8SOmair Javaid         return LLDB_INVALID_INDEX32;
633ea8c25a8SOmair Javaid 
634ea8c25a8SOmair Javaid     // Add new or update existing watchpoint
635ea8c25a8SOmair Javaid     if ((m_hwp_regs[wp_index].control & 1) == 0)
636ea8c25a8SOmair Javaid     {
6371fd2a8cfSOmair Javaid         // Update watchpoint in local cache
638*43507f57SOmair Javaid         m_hwp_regs[wp_index].real_addr = real_addr;
639ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].address = addr;
640ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].control = control_value;
641ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount = 1;
642ea8c25a8SOmair Javaid 
643ea8c25a8SOmair Javaid         // PTRACE call to set corresponding watchpoint register.
6443a56363aSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeWATCH);
6453a56363aSOmair Javaid 
6463a56363aSOmair Javaid         if (error.Fail())
647f24741d9SOmair Javaid         {
648f24741d9SOmair Javaid             m_hwp_regs[wp_index].address = 0;
649f24741d9SOmair Javaid             m_hwp_regs[wp_index].control &= ~1;
650f24741d9SOmair Javaid             m_hwp_regs[wp_index].refcount = 0;
651f24741d9SOmair Javaid 
6523a56363aSOmair Javaid             return LLDB_INVALID_INDEX32;
653ea8c25a8SOmair Javaid         }
654f24741d9SOmair Javaid     }
655ea8c25a8SOmair Javaid     else
656ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount++;
657ea8c25a8SOmair Javaid 
658ea8c25a8SOmair Javaid     return wp_index;
659ea8c25a8SOmair Javaid }
660ea8c25a8SOmair Javaid 
661ea8c25a8SOmair Javaid bool
662ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index)
663ea8c25a8SOmair Javaid {
664ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
665ea8c25a8SOmair Javaid 
666ea8c25a8SOmair Javaid     if (log)
667ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
668ea8c25a8SOmair Javaid 
6693a56363aSOmair Javaid     Error error;
6703a56363aSOmair Javaid 
6711fd2a8cfSOmair Javaid     // Read hardware breakpoint and watchpoint information.
6723a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
6733a56363aSOmair Javaid 
6743a56363aSOmair Javaid     if (error.Fail())
6753a56363aSOmair Javaid         return false;
676ea8c25a8SOmair Javaid 
677ea8c25a8SOmair Javaid     if (wp_index >= m_max_hwp_supported)
678ea8c25a8SOmair Javaid         return false;
679ea8c25a8SOmair Javaid 
680ea8c25a8SOmair Javaid     // Update reference count if multiple references.
681ea8c25a8SOmair Javaid     if (m_hwp_regs[wp_index].refcount > 1)
682ea8c25a8SOmair Javaid     {
683ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount--;
684ea8c25a8SOmair Javaid         return true;
685ea8c25a8SOmair Javaid     }
686ea8c25a8SOmair Javaid     else if (m_hwp_regs[wp_index].refcount == 1)
687ea8c25a8SOmair Javaid     {
688f24741d9SOmair Javaid         // Create a backup we can revert to in case of failure.
689f24741d9SOmair Javaid         lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
690f24741d9SOmair Javaid         uint32_t tempControl = m_hwp_regs[wp_index].control;
691f24741d9SOmair Javaid         uint32_t tempRefCount = m_hwp_regs[wp_index].refcount;
692f24741d9SOmair Javaid 
6931fd2a8cfSOmair Javaid         // Update watchpoint in local cache
694ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].control &= ~1;
695ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].address = 0;
696ea8c25a8SOmair Javaid         m_hwp_regs[wp_index].refcount = 0;
697ea8c25a8SOmair Javaid 
6981fd2a8cfSOmair Javaid         // Ptrace call to update hardware debug registers
6993a56363aSOmair Javaid         error = WriteHardwareDebugRegs(eDREGTypeWATCH);
7003a56363aSOmair Javaid 
7013a56363aSOmair Javaid         if (error.Fail())
702f24741d9SOmair Javaid         {
703f24741d9SOmair Javaid             m_hwp_regs[wp_index].control = tempControl;
704f24741d9SOmair Javaid             m_hwp_regs[wp_index].address = tempAddr;
705f24741d9SOmair Javaid             m_hwp_regs[wp_index].refcount = tempRefCount;
706f24741d9SOmair Javaid 
7073a56363aSOmair Javaid             return false;
708f24741d9SOmair Javaid         }
7093a56363aSOmair Javaid 
710ea8c25a8SOmair Javaid         return true;
711ea8c25a8SOmair Javaid     }
712ea8c25a8SOmair Javaid 
713ea8c25a8SOmair Javaid     return false;
714ea8c25a8SOmair Javaid }
715ea8c25a8SOmair Javaid 
716ea8c25a8SOmair Javaid Error
717ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints ()
718ea8c25a8SOmair Javaid {
719ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
720ea8c25a8SOmair Javaid 
721ea8c25a8SOmair Javaid     if (log)
722ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
723ea8c25a8SOmair Javaid 
7243a56363aSOmair Javaid     Error error;
7253a56363aSOmair Javaid 
7261fd2a8cfSOmair Javaid     // Read hardware breakpoint and watchpoint information.
7273a56363aSOmair Javaid     error = ReadHardwareDebugInfo ();
7283a56363aSOmair Javaid 
7293a56363aSOmair Javaid     if (error.Fail())
7303a56363aSOmair Javaid         return error;
731ea8c25a8SOmair Javaid 
732f24741d9SOmair Javaid     lldb::addr_t tempAddr = 0;
733f24741d9SOmair Javaid     uint32_t tempControl = 0, tempRefCount = 0;
734f24741d9SOmair Javaid 
735ea8c25a8SOmair Javaid     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
736ea8c25a8SOmair Javaid     {
737ea8c25a8SOmair Javaid         if (m_hwp_regs[i].control & 0x01)
738ea8c25a8SOmair Javaid         {
739f24741d9SOmair Javaid             // Create a backup we can revert to in case of failure.
740f24741d9SOmair Javaid             tempAddr = m_hwp_regs[i].address;
741f24741d9SOmair Javaid             tempControl = m_hwp_regs[i].control;
742f24741d9SOmair Javaid             tempRefCount = m_hwp_regs[i].refcount;
743f24741d9SOmair Javaid 
7441fd2a8cfSOmair Javaid             // Clear watchpoints in local cache
745ea8c25a8SOmair Javaid             m_hwp_regs[i].control &= ~1;
746ea8c25a8SOmair Javaid             m_hwp_regs[i].address = 0;
747ea8c25a8SOmair Javaid             m_hwp_regs[i].refcount = 0;
748ea8c25a8SOmair Javaid 
7491fd2a8cfSOmair Javaid             // Ptrace call to update hardware debug registers
7503a56363aSOmair Javaid             error = WriteHardwareDebugRegs(eDREGTypeWATCH);
7513a56363aSOmair Javaid 
7523a56363aSOmair Javaid             if (error.Fail())
753f24741d9SOmair Javaid             {
754f24741d9SOmair Javaid                 m_hwp_regs[i].control = tempControl;
755f24741d9SOmair Javaid                 m_hwp_regs[i].address = tempAddr;
756f24741d9SOmair Javaid                 m_hwp_regs[i].refcount = tempRefCount;
757f24741d9SOmair Javaid 
7583a56363aSOmair Javaid                 return error;
759ea8c25a8SOmair Javaid             }
760ea8c25a8SOmair Javaid         }
761f24741d9SOmair Javaid     }
762ea8c25a8SOmair Javaid 
763ea8c25a8SOmair Javaid     return Error();
764ea8c25a8SOmair Javaid }
765ea8c25a8SOmair Javaid 
766ea8c25a8SOmair Javaid uint32_t
767ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index)
768ea8c25a8SOmair Javaid {
769ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
770ea8c25a8SOmair Javaid 
771ea8c25a8SOmair Javaid     if (log)
772ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
773ea8c25a8SOmair Javaid     switch ((m_hwp_regs[wp_index].control >> 5) & 0xff)
774ea8c25a8SOmair Javaid     {
775ea8c25a8SOmair Javaid         case 0x01:
776ea8c25a8SOmair Javaid             return 1;
777ea8c25a8SOmair Javaid         case 0x03:
778ea8c25a8SOmair Javaid             return 2;
779ea8c25a8SOmair Javaid         case 0x0f:
780ea8c25a8SOmair Javaid             return 4;
781ea8c25a8SOmair Javaid         case 0xff:
782ea8c25a8SOmair Javaid             return 8;
783ea8c25a8SOmair Javaid         default:
784ea8c25a8SOmair Javaid             return 0;
785ea8c25a8SOmair Javaid     }
786ea8c25a8SOmair Javaid }
787ea8c25a8SOmair Javaid bool
788ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index)
789ea8c25a8SOmair Javaid {
790ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
791ea8c25a8SOmair Javaid 
792ea8c25a8SOmair Javaid     if (log)
793ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
794ea8c25a8SOmair Javaid 
795ea8c25a8SOmair Javaid     if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
796ea8c25a8SOmair Javaid         return true;
797ea8c25a8SOmair Javaid     else
798ea8c25a8SOmair Javaid         return false;
799ea8c25a8SOmair Javaid }
800ea8c25a8SOmair Javaid 
801ea8c25a8SOmair Javaid Error
802ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
803ea8c25a8SOmair Javaid {
804ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
805ea8c25a8SOmair Javaid 
806ea8c25a8SOmair Javaid     if (log)
807ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
808ea8c25a8SOmair Javaid 
809ea8c25a8SOmair Javaid     uint32_t watch_size;
810ea8c25a8SOmair Javaid     lldb::addr_t watch_addr;
811ea8c25a8SOmair Javaid 
812ea8c25a8SOmair Javaid     for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
813ea8c25a8SOmair Javaid     {
814ea8c25a8SOmair Javaid         watch_size = GetWatchpointSize (wp_index);
815ea8c25a8SOmair Javaid         watch_addr = m_hwp_regs[wp_index].address;
816ea8c25a8SOmair Javaid 
817ea8c25a8SOmair Javaid         if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
818ea8c25a8SOmair Javaid             && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
819ea8c25a8SOmair Javaid         {
820*43507f57SOmair Javaid             m_hwp_regs[wp_index].hit_addr = trap_addr;
821ea8c25a8SOmair Javaid             return Error();
822ea8c25a8SOmair Javaid         }
823ea8c25a8SOmair Javaid     }
824ea8c25a8SOmair Javaid 
825ea8c25a8SOmair Javaid     wp_index = LLDB_INVALID_INDEX32;
826ea8c25a8SOmair Javaid     return Error();
827ea8c25a8SOmair Javaid }
828ea8c25a8SOmair Javaid 
829ea8c25a8SOmair Javaid lldb::addr_t
830ea8c25a8SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index)
831ea8c25a8SOmair Javaid {
832ea8c25a8SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
833ea8c25a8SOmair Javaid 
834ea8c25a8SOmair Javaid     if (log)
835ea8c25a8SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
836ea8c25a8SOmair Javaid 
837ea8c25a8SOmair Javaid     if (wp_index >= m_max_hwp_supported)
838ea8c25a8SOmair Javaid         return LLDB_INVALID_ADDRESS;
839ea8c25a8SOmair Javaid 
840ea8c25a8SOmair Javaid     if (WatchpointIsEnabled(wp_index))
841*43507f57SOmair Javaid         return m_hwp_regs[wp_index].real_addr;
842*43507f57SOmair Javaid     else
843*43507f57SOmair Javaid         return LLDB_INVALID_ADDRESS;
844*43507f57SOmair Javaid }
845*43507f57SOmair Javaid 
846*43507f57SOmair Javaid lldb::addr_t
847*43507f57SOmair Javaid NativeRegisterContextLinux_arm64::GetWatchpointHitAddress (uint32_t wp_index)
848*43507f57SOmair Javaid {
849*43507f57SOmair Javaid     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
850*43507f57SOmair Javaid 
851*43507f57SOmair Javaid     if (log)
852*43507f57SOmair Javaid         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
853*43507f57SOmair Javaid 
854*43507f57SOmair Javaid     if (wp_index >= m_max_hwp_supported)
855*43507f57SOmair Javaid         return LLDB_INVALID_ADDRESS;
856*43507f57SOmair Javaid 
857*43507f57SOmair Javaid     if (WatchpointIsEnabled(wp_index))
858*43507f57SOmair Javaid         return m_hwp_regs[wp_index].hit_addr;
859ea8c25a8SOmair Javaid     else
860ea8c25a8SOmair Javaid         return LLDB_INVALID_ADDRESS;
861ea8c25a8SOmair Javaid }
862ea8c25a8SOmair Javaid 
863068f8a7eSTamas Berghammer Error
8641fd2a8cfSOmair Javaid NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo()
865ea8c25a8SOmair Javaid {
8661fd2a8cfSOmair Javaid     if (!m_refresh_hwdebug_info)
8671fd2a8cfSOmair Javaid     {
8681fd2a8cfSOmair Javaid         return Error();
8691fd2a8cfSOmair Javaid     }
8701fd2a8cfSOmair Javaid 
871c7512fdcSPavel Labath     ::pid_t tid = m_thread.GetID();
872ea8c25a8SOmair Javaid 
873c7512fdcSPavel Labath     int regset = NT_ARM_HW_WATCH;
874c7512fdcSPavel Labath     struct iovec ioVec;
875c7512fdcSPavel Labath     struct user_hwdebug_state dreg_state;
876c7512fdcSPavel Labath     Error error;
877c7512fdcSPavel Labath 
878c7512fdcSPavel Labath     ioVec.iov_base = &dreg_state;
879c7512fdcSPavel Labath     ioVec.iov_len = sizeof (dreg_state);
8804a9babb2SPavel Labath     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
8813a56363aSOmair Javaid 
8823a56363aSOmair Javaid     if (error.Fail())
8833a56363aSOmair Javaid         return error;
8843a56363aSOmair Javaid 
8851fd2a8cfSOmair Javaid     m_max_hwp_supported = dreg_state.dbg_info & 0xff;
886c7512fdcSPavel Labath 
887c7512fdcSPavel Labath     regset = NT_ARM_HW_BREAK;
8884a9babb2SPavel Labath     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
8891fd2a8cfSOmair Javaid 
8903a56363aSOmair Javaid     if (error.Fail())
8913a56363aSOmair Javaid         return error;
8923a56363aSOmair Javaid 
8933a56363aSOmair Javaid     m_max_hbp_supported = dreg_state.dbg_info & 0xff;
8941fd2a8cfSOmair Javaid     m_refresh_hwdebug_info = false;
895c7512fdcSPavel Labath 
896c7512fdcSPavel Labath     return error;
897ea8c25a8SOmair Javaid }
898068f8a7eSTamas Berghammer 
899068f8a7eSTamas Berghammer Error
9001fd2a8cfSOmair Javaid NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType)
901068f8a7eSTamas Berghammer {
902c7512fdcSPavel Labath     struct iovec ioVec;
903c7512fdcSPavel Labath     struct user_hwdebug_state dreg_state;
904c7512fdcSPavel Labath     Error error;
905c7512fdcSPavel Labath 
906c7512fdcSPavel Labath     memset (&dreg_state, 0, sizeof (dreg_state));
907c7512fdcSPavel Labath     ioVec.iov_base = &dreg_state;
908c7512fdcSPavel Labath 
9091fd2a8cfSOmair Javaid     if (hwbType == eDREGTypeWATCH)
910c7512fdcSPavel Labath     {
9111fd2a8cfSOmair Javaid         hwbType = NT_ARM_HW_WATCH;
9125cf948d2SOmair Javaid         ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad)
9135cf948d2SOmair Javaid                 + (sizeof (dreg_state.dbg_regs [0]) * m_max_hwp_supported);
9141fd2a8cfSOmair Javaid 
9151fd2a8cfSOmair Javaid         for (uint32_t i = 0; i < m_max_hwp_supported; i++)
9161fd2a8cfSOmair Javaid         {
9171fd2a8cfSOmair Javaid             dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
9181fd2a8cfSOmair Javaid             dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
9191fd2a8cfSOmair Javaid         }
9201fd2a8cfSOmair Javaid     }
9211fd2a8cfSOmair Javaid     else
9221fd2a8cfSOmair Javaid     {
9231fd2a8cfSOmair Javaid         hwbType = NT_ARM_HW_BREAK;
9245cf948d2SOmair Javaid         ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad)
9255cf948d2SOmair Javaid                 + (sizeof (dreg_state.dbg_regs [0]) * m_max_hbp_supported);
9261fd2a8cfSOmair Javaid 
9271fd2a8cfSOmair Javaid         for (uint32_t i = 0; i < m_max_hbp_supported; i++)
9281fd2a8cfSOmair Javaid         {
9291fd2a8cfSOmair Javaid             dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address;
9301fd2a8cfSOmair Javaid             dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control;
9311fd2a8cfSOmair Javaid         }
932068f8a7eSTamas Berghammer     }
933068f8a7eSTamas Berghammer 
9341fd2a8cfSOmair Javaid     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &hwbType, &ioVec, ioVec.iov_len);
935c7512fdcSPavel Labath }
936c7512fdcSPavel Labath 
937c7512fdcSPavel Labath Error
938c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset,
939068f8a7eSTamas Berghammer                                                       const char* reg_name,
940068f8a7eSTamas Berghammer                                                       uint32_t size,
941068f8a7eSTamas Berghammer                                                       RegisterValue &value)
942068f8a7eSTamas Berghammer {
943c7512fdcSPavel Labath     Error error;
944c7512fdcSPavel Labath     if (offset > sizeof(struct user_pt_regs))
945c7512fdcSPavel Labath     {
946c7512fdcSPavel Labath         uintptr_t offset = offset - sizeof(struct user_pt_regs);
947c7512fdcSPavel Labath         if (offset > sizeof(struct user_fpsimd_state))
948c7512fdcSPavel Labath         {
949c7512fdcSPavel Labath             error.SetErrorString("invalid offset value");
950c7512fdcSPavel Labath             return error;
951c7512fdcSPavel Labath         }
952c7512fdcSPavel Labath         elf_fpregset_t regs;
953c7512fdcSPavel Labath         int regset = NT_FPREGSET;
954c7512fdcSPavel Labath         struct iovec ioVec;
955c7512fdcSPavel Labath 
956c7512fdcSPavel Labath         ioVec.iov_base = &regs;
957c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
9584a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper(
9594a9babb2SPavel Labath                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
960c7512fdcSPavel Labath         if (error.Success())
961c7512fdcSPavel Labath         {
962c7512fdcSPavel Labath             ArchSpec arch;
963c7512fdcSPavel Labath             if (m_thread.GetProcess()->GetArchitecture(arch))
964c7512fdcSPavel Labath                 value.SetBytes((void *)(((unsigned char *)(&regs)) + offset), 16, arch.GetByteOrder());
965c7512fdcSPavel Labath             else
966c7512fdcSPavel Labath                 error.SetErrorString("failed to get architecture");
967c7512fdcSPavel Labath         }
968c7512fdcSPavel Labath     }
969c7512fdcSPavel Labath     else
970c7512fdcSPavel Labath     {
971c7512fdcSPavel Labath         elf_gregset_t regs;
972c7512fdcSPavel Labath         int regset = NT_PRSTATUS;
973c7512fdcSPavel Labath         struct iovec ioVec;
974c7512fdcSPavel Labath 
975c7512fdcSPavel Labath         ioVec.iov_base = &regs;
976c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
9774a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper(
9784a9babb2SPavel Labath                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
979c7512fdcSPavel Labath         if (error.Success())
980c7512fdcSPavel Labath         {
981c7512fdcSPavel Labath             ArchSpec arch;
982c7512fdcSPavel Labath             if (m_thread.GetProcess()->GetArchitecture(arch))
983c7512fdcSPavel Labath                 value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder());
984c7512fdcSPavel Labath             else
985c7512fdcSPavel Labath                 error.SetErrorString("failed to get architecture");
986c7512fdcSPavel Labath         }
987c7512fdcSPavel Labath     }
988c7512fdcSPavel Labath     return error;
989068f8a7eSTamas Berghammer }
990068f8a7eSTamas Berghammer 
991c7512fdcSPavel Labath Error
992c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset,
993068f8a7eSTamas Berghammer                                                        const char* reg_name,
994068f8a7eSTamas Berghammer                                                        const RegisterValue &value)
995068f8a7eSTamas Berghammer {
996c7512fdcSPavel Labath     Error error;
997c7512fdcSPavel Labath     ::pid_t tid = m_thread.GetID();
998c7512fdcSPavel Labath     if (offset > sizeof(struct user_pt_regs))
999c7512fdcSPavel Labath     {
1000c7512fdcSPavel Labath         uintptr_t offset = offset - sizeof(struct user_pt_regs);
1001c7512fdcSPavel Labath         if (offset > sizeof(struct user_fpsimd_state))
1002c7512fdcSPavel Labath         {
1003c7512fdcSPavel Labath             error.SetErrorString("invalid offset value");
1004c7512fdcSPavel Labath             return error;
1005c7512fdcSPavel Labath         }
1006c7512fdcSPavel Labath         elf_fpregset_t regs;
1007c7512fdcSPavel Labath         int regset = NT_FPREGSET;
1008c7512fdcSPavel Labath         struct iovec ioVec;
1009c7512fdcSPavel Labath 
1010c7512fdcSPavel Labath         ioVec.iov_base = &regs;
1011c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
10124a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
1013c7512fdcSPavel Labath 
1014c7512fdcSPavel Labath         if (error.Success())
1015c7512fdcSPavel Labath         {
1016c7512fdcSPavel Labath             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 16);
10174a9babb2SPavel Labath             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
1018c7512fdcSPavel Labath         }
1019c7512fdcSPavel Labath     }
1020c7512fdcSPavel Labath     else
1021c7512fdcSPavel Labath     {
1022c7512fdcSPavel Labath         elf_gregset_t regs;
1023c7512fdcSPavel Labath         int regset = NT_PRSTATUS;
1024c7512fdcSPavel Labath         struct iovec ioVec;
1025c7512fdcSPavel Labath 
1026c7512fdcSPavel Labath         ioVec.iov_base = &regs;
1027c7512fdcSPavel Labath         ioVec.iov_len = sizeof regs;
10284a9babb2SPavel Labath         error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
1029c7512fdcSPavel Labath         if (error.Success())
1030c7512fdcSPavel Labath         {
1031c7512fdcSPavel Labath             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 8);
10324a9babb2SPavel Labath             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
1033c7512fdcSPavel Labath         }
1034c7512fdcSPavel Labath     }
1035c7512fdcSPavel Labath     return error;
1036068f8a7eSTamas Berghammer }
1037068f8a7eSTamas Berghammer 
1038c7512fdcSPavel Labath Error
1039c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size)
1040068f8a7eSTamas Berghammer {
1041c7512fdcSPavel Labath     int regset = NT_PRSTATUS;
1042c7512fdcSPavel Labath     struct iovec ioVec;
1043c7512fdcSPavel Labath     Error error;
1044c7512fdcSPavel Labath 
1045c7512fdcSPavel Labath     ioVec.iov_base = buf;
1046c7512fdcSPavel Labath     ioVec.iov_len = buf_size;
10474a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
1048068f8a7eSTamas Berghammer }
1049068f8a7eSTamas Berghammer 
1050c7512fdcSPavel Labath Error
1051c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size)
1052068f8a7eSTamas Berghammer {
1053c7512fdcSPavel Labath     int regset = NT_PRSTATUS;
1054c7512fdcSPavel Labath     struct iovec ioVec;
1055c7512fdcSPavel Labath     Error error;
1056c7512fdcSPavel Labath 
1057c7512fdcSPavel Labath     ioVec.iov_base = buf;
1058c7512fdcSPavel Labath     ioVec.iov_len = buf_size;
10594a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
1060068f8a7eSTamas Berghammer }
1061068f8a7eSTamas Berghammer 
1062c7512fdcSPavel Labath Error
1063c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size)
1064068f8a7eSTamas Berghammer {
1065c7512fdcSPavel Labath     int regset = NT_FPREGSET;
1066c7512fdcSPavel Labath     struct iovec ioVec;
1067c7512fdcSPavel Labath     Error error;
1068c7512fdcSPavel Labath 
1069c7512fdcSPavel Labath     ioVec.iov_base = buf;
1070c7512fdcSPavel Labath     ioVec.iov_len = buf_size;
10714a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
1072068f8a7eSTamas Berghammer }
1073068f8a7eSTamas Berghammer 
1074c7512fdcSPavel Labath Error
1075c7512fdcSPavel Labath NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size)
1076068f8a7eSTamas Berghammer {
1077c7512fdcSPavel Labath     int regset = NT_FPREGSET;
1078c7512fdcSPavel Labath     struct iovec ioVec;
1079c7512fdcSPavel Labath     Error error;
1080c7512fdcSPavel Labath 
1081c7512fdcSPavel Labath     ioVec.iov_base = buf;
1082c7512fdcSPavel Labath     ioVec.iov_len = buf_size;
10834a9babb2SPavel Labath     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
1084068f8a7eSTamas Berghammer }
1085068f8a7eSTamas Berghammer 
1086c40e7b17STamas Berghammer uint32_t
1087c40e7b17STamas Berghammer NativeRegisterContextLinux_arm64::CalculateFprOffset(const RegisterInfo* reg_info) const
1088c40e7b17STamas Berghammer {
1089c40e7b17STamas Berghammer     return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
1090c40e7b17STamas Berghammer }
1091c40e7b17STamas Berghammer 
1092068f8a7eSTamas Berghammer #endif // defined (__arm64__) || defined (__aarch64__)
1093