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 
101e209fccSTamas Berghammer #include "NativeRegisterContextLinux_arm64.h"
111e209fccSTamas Berghammer 
121e209fccSTamas Berghammer #include "lldb/lldb-private-forward.h"
131e209fccSTamas Berghammer #include "lldb/Core/DataBufferHeap.h"
141e209fccSTamas Berghammer #include "lldb/Core/Error.h"
151e209fccSTamas Berghammer #include "lldb/Core/RegisterValue.h"
161e209fccSTamas Berghammer #include "lldb/Host/common/NativeProcessProtocol.h"
171e209fccSTamas Berghammer #include "lldb/Host/common/NativeThreadProtocol.h"
181e209fccSTamas Berghammer #include "Plugins/Process/Linux/NativeProcessLinux.h"
191e209fccSTamas Berghammer 
201e209fccSTamas Berghammer #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr))
211e209fccSTamas Berghammer 
221e209fccSTamas Berghammer using namespace lldb;
231e209fccSTamas Berghammer using namespace lldb_private;
24*db264a6dSTamas Berghammer using namespace lldb_private::process_linux;
251e209fccSTamas Berghammer 
261e209fccSTamas Berghammer // ARM64 general purpose registers.
271e209fccSTamas Berghammer static const uint32_t g_gpr_regnums_arm64[] =
281e209fccSTamas Berghammer {
291e209fccSTamas Berghammer     gpr_x0_arm64,
301e209fccSTamas Berghammer     gpr_x1_arm64,
311e209fccSTamas Berghammer     gpr_x2_arm64,
321e209fccSTamas Berghammer     gpr_x3_arm64,
331e209fccSTamas Berghammer     gpr_x4_arm64,
341e209fccSTamas Berghammer     gpr_x5_arm64,
351e209fccSTamas Berghammer     gpr_x6_arm64,
361e209fccSTamas Berghammer     gpr_x7_arm64,
371e209fccSTamas Berghammer     gpr_x8_arm64,
381e209fccSTamas Berghammer     gpr_x9_arm64,
391e209fccSTamas Berghammer     gpr_x10_arm64,
401e209fccSTamas Berghammer     gpr_x11_arm64,
411e209fccSTamas Berghammer     gpr_x12_arm64,
421e209fccSTamas Berghammer     gpr_x13_arm64,
431e209fccSTamas Berghammer     gpr_x14_arm64,
441e209fccSTamas Berghammer     gpr_x15_arm64,
451e209fccSTamas Berghammer     gpr_x16_arm64,
461e209fccSTamas Berghammer     gpr_x17_arm64,
471e209fccSTamas Berghammer     gpr_x18_arm64,
481e209fccSTamas Berghammer     gpr_x19_arm64,
491e209fccSTamas Berghammer     gpr_x20_arm64,
501e209fccSTamas Berghammer     gpr_x21_arm64,
511e209fccSTamas Berghammer     gpr_x22_arm64,
521e209fccSTamas Berghammer     gpr_x23_arm64,
531e209fccSTamas Berghammer     gpr_x24_arm64,
541e209fccSTamas Berghammer     gpr_x25_arm64,
551e209fccSTamas Berghammer     gpr_x26_arm64,
561e209fccSTamas Berghammer     gpr_x27_arm64,
571e209fccSTamas Berghammer     gpr_x28_arm64,
581e209fccSTamas Berghammer     gpr_fp_arm64,
591e209fccSTamas Berghammer     gpr_lr_arm64,
601e209fccSTamas Berghammer     gpr_sp_arm64,
611e209fccSTamas Berghammer     gpr_pc_arm64,
621e209fccSTamas Berghammer     gpr_cpsr_arm64,
631e209fccSTamas Berghammer     LLDB_INVALID_REGNUM // register sets need to end with this flag
641e209fccSTamas Berghammer };
651e209fccSTamas Berghammer static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \
661e209fccSTamas Berghammer               "g_gpr_regnums_arm64 has wrong number of register infos");
671e209fccSTamas Berghammer 
681e209fccSTamas Berghammer // ARM64 floating point registers.
691e209fccSTamas Berghammer static const uint32_t g_fpu_regnums_arm64[] =
701e209fccSTamas Berghammer {
711e209fccSTamas Berghammer     fpu_v0_arm64,
721e209fccSTamas Berghammer     fpu_v1_arm64,
731e209fccSTamas Berghammer     fpu_v2_arm64,
741e209fccSTamas Berghammer     fpu_v3_arm64,
751e209fccSTamas Berghammer     fpu_v4_arm64,
761e209fccSTamas Berghammer     fpu_v5_arm64,
771e209fccSTamas Berghammer     fpu_v6_arm64,
781e209fccSTamas Berghammer     fpu_v7_arm64,
791e209fccSTamas Berghammer     fpu_v8_arm64,
801e209fccSTamas Berghammer     fpu_v9_arm64,
811e209fccSTamas Berghammer     fpu_v10_arm64,
821e209fccSTamas Berghammer     fpu_v11_arm64,
831e209fccSTamas Berghammer     fpu_v12_arm64,
841e209fccSTamas Berghammer     fpu_v13_arm64,
851e209fccSTamas Berghammer     fpu_v14_arm64,
861e209fccSTamas Berghammer     fpu_v15_arm64,
871e209fccSTamas Berghammer     fpu_v16_arm64,
881e209fccSTamas Berghammer     fpu_v17_arm64,
891e209fccSTamas Berghammer     fpu_v18_arm64,
901e209fccSTamas Berghammer     fpu_v19_arm64,
911e209fccSTamas Berghammer     fpu_v20_arm64,
921e209fccSTamas Berghammer     fpu_v21_arm64,
931e209fccSTamas Berghammer     fpu_v22_arm64,
941e209fccSTamas Berghammer     fpu_v23_arm64,
951e209fccSTamas Berghammer     fpu_v24_arm64,
961e209fccSTamas Berghammer     fpu_v25_arm64,
971e209fccSTamas Berghammer     fpu_v26_arm64,
981e209fccSTamas Berghammer     fpu_v27_arm64,
991e209fccSTamas Berghammer     fpu_v28_arm64,
1001e209fccSTamas Berghammer     fpu_v29_arm64,
1011e209fccSTamas Berghammer     fpu_v30_arm64,
1021e209fccSTamas Berghammer     fpu_v31_arm64,
1031e209fccSTamas Berghammer     fpu_fpsr_arm64,
1041e209fccSTamas Berghammer     fpu_fpcr_arm64,
1051e209fccSTamas Berghammer     LLDB_INVALID_REGNUM // register sets need to end with this flag
1061e209fccSTamas Berghammer };
1071e209fccSTamas Berghammer static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \
1081e209fccSTamas Berghammer               "g_fpu_regnums_arm64 has wrong number of register infos");
1091e209fccSTamas Berghammer 
1101e209fccSTamas Berghammer namespace {
1111e209fccSTamas Berghammer     // Number of register sets provided by this context.
1121e209fccSTamas Berghammer     enum
1131e209fccSTamas Berghammer     {
1141e209fccSTamas Berghammer         k_num_register_sets = 2
1151e209fccSTamas Berghammer     };
1161e209fccSTamas Berghammer }
1171e209fccSTamas Berghammer 
1181e209fccSTamas Berghammer // Register sets for ARM64.
119*db264a6dSTamas Berghammer static const RegisterSet
1201e209fccSTamas Berghammer g_reg_sets_arm64[k_num_register_sets] =
1211e209fccSTamas Berghammer {
1221e209fccSTamas Berghammer     { "General Purpose Registers",  "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 },
1231e209fccSTamas Berghammer     { "Floating Point Registers",   "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 }
1241e209fccSTamas Berghammer };
1251e209fccSTamas Berghammer 
1261e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (
1271e209fccSTamas Berghammer         NativeThreadProtocol &native_thread,
1281e209fccSTamas Berghammer         uint32_t concrete_frame_idx,
1291e209fccSTamas Berghammer         RegisterInfoInterface *reg_info_interface_p) :
1301e209fccSTamas Berghammer     NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p)
1311e209fccSTamas Berghammer {
1321e209fccSTamas Berghammer     switch (reg_info_interface_p->m_target_arch.GetMachine())
1331e209fccSTamas Berghammer     {
1341e209fccSTamas Berghammer         case llvm::Triple::aarch64:
1351e209fccSTamas Berghammer             m_reg_info.num_registers     = k_num_registers_arm64;
1361e209fccSTamas Berghammer             m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64;
1371e209fccSTamas Berghammer             m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64;
1381e209fccSTamas Berghammer             m_reg_info.last_gpr          = k_last_gpr_arm64;
1391e209fccSTamas Berghammer             m_reg_info.first_fpr         = k_first_fpr_arm64;
1401e209fccSTamas Berghammer             m_reg_info.last_fpr          = k_last_fpr_arm64;
1411e209fccSTamas Berghammer             m_reg_info.first_fpr_v       = fpu_v0_arm64;
1421e209fccSTamas Berghammer             m_reg_info.last_fpr_v        = fpu_v31_arm64;
1431e209fccSTamas Berghammer             m_reg_info.gpr_flags         = gpr_cpsr_arm64;
1441e209fccSTamas Berghammer             break;
1451e209fccSTamas Berghammer         default:
1461e209fccSTamas Berghammer             assert(false && "Unhandled target architecture.");
1471e209fccSTamas Berghammer             break;
1481e209fccSTamas Berghammer     }
1491e209fccSTamas Berghammer 
1501e209fccSTamas Berghammer     ::memset(&m_fpr, 0, sizeof (m_fpr));
1511e209fccSTamas Berghammer     ::memset(&m_gpr_arm64, 0, sizeof (m_gpr_arm64));
1521e209fccSTamas Berghammer }
1531e209fccSTamas Berghammer 
1541e209fccSTamas Berghammer uint32_t
1551e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetRegisterSetCount () const
1561e209fccSTamas Berghammer {
1571e209fccSTamas Berghammer     return k_num_register_sets;
1581e209fccSTamas Berghammer }
1591e209fccSTamas Berghammer 
160*db264a6dSTamas Berghammer const RegisterSet *
1611e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetRegisterSet (uint32_t set_index) const
1621e209fccSTamas Berghammer {
1631e209fccSTamas Berghammer     if (set_index < k_num_register_sets)
1641e209fccSTamas Berghammer         return &g_reg_sets_arm64[set_index];
1651e209fccSTamas Berghammer 
1661e209fccSTamas Berghammer     return nullptr;
1671e209fccSTamas Berghammer }
1681e209fccSTamas Berghammer 
169*db264a6dSTamas Berghammer Error
1701e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
1711e209fccSTamas Berghammer {
1721e209fccSTamas Berghammer     Error error;
1731e209fccSTamas Berghammer 
1741e209fccSTamas Berghammer     if (!reg_info)
1751e209fccSTamas Berghammer     {
1761e209fccSTamas Berghammer         error.SetErrorString ("reg_info NULL");
1771e209fccSTamas Berghammer         return error;
1781e209fccSTamas Berghammer     }
1791e209fccSTamas Berghammer 
1801e209fccSTamas Berghammer     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
1811e209fccSTamas Berghammer 
1821e209fccSTamas Berghammer     if (IsFPR(reg))
1831e209fccSTamas Berghammer     {
1841e209fccSTamas Berghammer         if (!ReadFPR())
1851e209fccSTamas Berghammer         {
1861e209fccSTamas Berghammer             error.SetErrorString ("failed to read floating point register");
1871e209fccSTamas Berghammer             return error;
1881e209fccSTamas Berghammer         }
1891e209fccSTamas Berghammer     }
1901e209fccSTamas Berghammer     else
1911e209fccSTamas Berghammer     {
1921e209fccSTamas Berghammer         uint32_t full_reg = reg;
1931e209fccSTamas Berghammer         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
1941e209fccSTamas Berghammer 
1951e209fccSTamas Berghammer         if (is_subreg)
1961e209fccSTamas Berghammer         {
1971e209fccSTamas Berghammer             // Read the full aligned 64-bit register.
1981e209fccSTamas Berghammer             full_reg = reg_info->invalidate_regs[0];
1991e209fccSTamas Berghammer         }
2001e209fccSTamas Berghammer 
2011e209fccSTamas Berghammer         error = ReadRegisterRaw(full_reg, reg_value);
2021e209fccSTamas Berghammer 
2031e209fccSTamas Berghammer         if (error.Success ())
2041e209fccSTamas Berghammer         {
2051e209fccSTamas Berghammer             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
2061e209fccSTamas Berghammer             if (is_subreg && (reg_info->byte_offset & 0x1))
2071e209fccSTamas Berghammer                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
2081e209fccSTamas Berghammer 
2091e209fccSTamas Berghammer             // If our return byte size was greater than the return value reg size, then
2101e209fccSTamas Berghammer             // use the type specified by reg_info rather than the uint64_t default
2111e209fccSTamas Berghammer             if (reg_value.GetByteSize() > reg_info->byte_size)
2121e209fccSTamas Berghammer                 reg_value.SetType(reg_info);
2131e209fccSTamas Berghammer         }
2141e209fccSTamas Berghammer         return error;
2151e209fccSTamas Berghammer     }
2161e209fccSTamas Berghammer 
2171e209fccSTamas Berghammer     // Get pointer to m_fpr variable and set the data from it.
2181e209fccSTamas Berghammer     assert (reg_info->byte_offset < sizeof m_fpr);
2191e209fccSTamas Berghammer     uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
2201e209fccSTamas Berghammer     switch (reg_info->byte_size)
2211e209fccSTamas Berghammer     {
2221e209fccSTamas Berghammer         case 2:
2231e209fccSTamas Berghammer             reg_value.SetUInt16(*(uint16_t *)src);
2241e209fccSTamas Berghammer             break;
2251e209fccSTamas Berghammer         case 4:
2261e209fccSTamas Berghammer             reg_value.SetUInt32(*(uint32_t *)src);
2271e209fccSTamas Berghammer             break;
2281e209fccSTamas Berghammer         case 8:
2291e209fccSTamas Berghammer             reg_value.SetUInt64(*(uint64_t *)src);
2301e209fccSTamas Berghammer             break;
2311e209fccSTamas Berghammer         default:
2321e209fccSTamas Berghammer             assert(false && "Unhandled data size.");
2331e209fccSTamas Berghammer             error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
2341e209fccSTamas Berghammer             break;
2351e209fccSTamas Berghammer     }
2361e209fccSTamas Berghammer 
2371e209fccSTamas Berghammer     return error;
2381e209fccSTamas Berghammer }
2391e209fccSTamas Berghammer 
240*db264a6dSTamas Berghammer Error
2411e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
2421e209fccSTamas Berghammer {
2431e209fccSTamas Berghammer     if (!reg_info)
2441e209fccSTamas Berghammer         return Error ("reg_info NULL");
2451e209fccSTamas Berghammer 
2461e209fccSTamas Berghammer     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
2471e209fccSTamas Berghammer     if (reg_index == LLDB_INVALID_REGNUM)
2481e209fccSTamas Berghammer         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
2491e209fccSTamas Berghammer 
2501e209fccSTamas Berghammer     if (IsGPR(reg_index))
2511e209fccSTamas Berghammer         return WriteRegisterRaw(reg_index, reg_value);
2521e209fccSTamas Berghammer 
2531e209fccSTamas Berghammer     if (IsFPR(reg_index))
2541e209fccSTamas Berghammer     {
2551e209fccSTamas Berghammer         // Get pointer to m_fpr variable and set the data to it.
2561e209fccSTamas Berghammer         assert (reg_info->byte_offset < sizeof(m_fpr));
2571e209fccSTamas Berghammer         uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
2581e209fccSTamas Berghammer         switch (reg_info->byte_size)
2591e209fccSTamas Berghammer         {
2601e209fccSTamas Berghammer             case 2:
2611e209fccSTamas Berghammer                 *(uint16_t *)dst = reg_value.GetAsUInt16();
2621e209fccSTamas Berghammer                 break;
2631e209fccSTamas Berghammer             case 4:
2641e209fccSTamas Berghammer                 *(uint32_t *)dst = reg_value.GetAsUInt32();
2651e209fccSTamas Berghammer                 break;
2661e209fccSTamas Berghammer             case 8:
2671e209fccSTamas Berghammer                 *(uint64_t *)dst = reg_value.GetAsUInt64();
2681e209fccSTamas Berghammer                 break;
2691e209fccSTamas Berghammer             default:
2701e209fccSTamas Berghammer                 assert(false && "Unhandled data size.");
2711e209fccSTamas Berghammer                 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
2721e209fccSTamas Berghammer         }
2731e209fccSTamas Berghammer 
2741e209fccSTamas Berghammer         if (!WriteFPR())
2751e209fccSTamas Berghammer         {
2761e209fccSTamas Berghammer             return Error ("NativeRegisterContextLinux_arm64::WriteRegister: WriteFPR failed");
2771e209fccSTamas Berghammer         }
2781e209fccSTamas Berghammer 
2791e209fccSTamas Berghammer         return Error ();
2801e209fccSTamas Berghammer     }
2811e209fccSTamas Berghammer 
2821e209fccSTamas Berghammer     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
2831e209fccSTamas Berghammer }
2841e209fccSTamas Berghammer 
285*db264a6dSTamas Berghammer Error
2861e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
2871e209fccSTamas Berghammer {
2881e209fccSTamas Berghammer     Error error;
2891e209fccSTamas Berghammer 
290*db264a6dSTamas Berghammer     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
2911e209fccSTamas Berghammer     if (!data_sp)
2921e209fccSTamas Berghammer         return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
2931e209fccSTamas Berghammer 
2941e209fccSTamas Berghammer     if (!ReadGPR ())
2951e209fccSTamas Berghammer     {
2961e209fccSTamas Berghammer         error.SetErrorString ("ReadGPR() failed");
2971e209fccSTamas Berghammer         return error;
2981e209fccSTamas Berghammer     }
2991e209fccSTamas Berghammer 
3001e209fccSTamas Berghammer     if (!ReadFPR ())
3011e209fccSTamas Berghammer     {
3021e209fccSTamas Berghammer         error.SetErrorString ("ReadFPR() failed");
3031e209fccSTamas Berghammer         return error;
3041e209fccSTamas Berghammer     }
3051e209fccSTamas Berghammer 
3061e209fccSTamas Berghammer     uint8_t *dst = data_sp->GetBytes ();
3071e209fccSTamas Berghammer     if (dst == nullptr)
3081e209fccSTamas Berghammer     {
3091e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
3101e209fccSTamas Berghammer         return error;
3111e209fccSTamas Berghammer     }
3121e209fccSTamas Berghammer 
3131e209fccSTamas Berghammer     ::memcpy (dst, &m_gpr_arm64, GetGPRSize());
3141e209fccSTamas Berghammer     dst += GetGPRSize();
3151e209fccSTamas Berghammer     ::memcpy (dst, &m_fpr, sizeof(m_fpr));
3161e209fccSTamas Berghammer 
3171e209fccSTamas Berghammer     return error;
3181e209fccSTamas Berghammer }
3191e209fccSTamas Berghammer 
320*db264a6dSTamas Berghammer Error
3211e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
3221e209fccSTamas Berghammer {
3231e209fccSTamas Berghammer     Error error;
3241e209fccSTamas Berghammer 
3251e209fccSTamas Berghammer     if (!data_sp)
3261e209fccSTamas Berghammer     {
3271e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
3281e209fccSTamas Berghammer         return error;
3291e209fccSTamas Berghammer     }
3301e209fccSTamas Berghammer 
3311e209fccSTamas Berghammer     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
3321e209fccSTamas Berghammer     {
3331e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
3341e209fccSTamas Berghammer         return error;
3351e209fccSTamas Berghammer     }
3361e209fccSTamas Berghammer 
3371e209fccSTamas Berghammer 
3381e209fccSTamas Berghammer     uint8_t *src = data_sp->GetBytes ();
3391e209fccSTamas Berghammer     if (src == nullptr)
3401e209fccSTamas Berghammer     {
3411e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
3421e209fccSTamas Berghammer         return error;
3431e209fccSTamas Berghammer     }
3441e209fccSTamas Berghammer     ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ());
3451e209fccSTamas Berghammer 
3461e209fccSTamas Berghammer     if (!WriteGPR ())
3471e209fccSTamas Berghammer     {
3481e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__);
3491e209fccSTamas Berghammer         return error;
3501e209fccSTamas Berghammer     }
3511e209fccSTamas Berghammer 
3521e209fccSTamas Berghammer     src += GetRegisterInfoInterface ().GetGPRSize ();
3531e209fccSTamas Berghammer     ::memcpy (&m_fpr, src, sizeof(m_fpr));
3541e209fccSTamas Berghammer 
3551e209fccSTamas Berghammer     if (!WriteFPR ())
3561e209fccSTamas Berghammer     {
3571e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__);
3581e209fccSTamas Berghammer         return error;
3591e209fccSTamas Berghammer     }
3601e209fccSTamas Berghammer 
3611e209fccSTamas Berghammer     return error;
3621e209fccSTamas Berghammer }
3631e209fccSTamas Berghammer 
364*db264a6dSTamas Berghammer Error
3651e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteRegisterRaw (uint32_t reg_index, const RegisterValue &reg_value)
3661e209fccSTamas Berghammer {
3671e209fccSTamas Berghammer     Error error;
3681e209fccSTamas Berghammer 
3691e209fccSTamas Berghammer     uint32_t reg_to_write = reg_index;
3701e209fccSTamas Berghammer     RegisterValue value_to_write = reg_value;
3711e209fccSTamas Berghammer 
3721e209fccSTamas Berghammer     // Check if this is a subregister of a full register.
3731e209fccSTamas Berghammer     const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
3741e209fccSTamas Berghammer     if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
3751e209fccSTamas Berghammer     {
3761e209fccSTamas Berghammer         RegisterValue full_value;
3771e209fccSTamas Berghammer         uint32_t full_reg = reg_info->invalidate_regs[0];
3781e209fccSTamas Berghammer         const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
3791e209fccSTamas Berghammer 
3801e209fccSTamas Berghammer         // Read the full register.
3811e209fccSTamas Berghammer         error = ReadRegister(full_reg_info, full_value);
3821e209fccSTamas Berghammer         if (error.Fail ())
3831e209fccSTamas Berghammer             return error;
3841e209fccSTamas Berghammer 
3851e209fccSTamas Berghammer         lldb::ByteOrder byte_order = GetByteOrder();
3861e209fccSTamas Berghammer         uint8_t dst[RegisterValue::kMaxRegisterByteSize];
3871e209fccSTamas Berghammer 
3881e209fccSTamas Berghammer         // Get the bytes for the full register.
3891e209fccSTamas Berghammer         const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
3901e209fccSTamas Berghammer                                                                dst,
3911e209fccSTamas Berghammer                                                                sizeof(dst),
3921e209fccSTamas Berghammer                                                                byte_order,
3931e209fccSTamas Berghammer                                                                error);
3941e209fccSTamas Berghammer         if (error.Success() && dest_size)
3951e209fccSTamas Berghammer         {
3961e209fccSTamas Berghammer             uint8_t src[RegisterValue::kMaxRegisterByteSize];
3971e209fccSTamas Berghammer 
3981e209fccSTamas Berghammer             // Get the bytes for the source data.
3991e209fccSTamas Berghammer             const uint32_t src_size = reg_value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
4001e209fccSTamas Berghammer             if (error.Success() && src_size && (src_size < dest_size))
4011e209fccSTamas Berghammer             {
4021e209fccSTamas Berghammer                 // Copy the src bytes to the destination.
4031e209fccSTamas Berghammer                 memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
4041e209fccSTamas Berghammer                 // Set this full register as the value to write.
4051e209fccSTamas Berghammer                 value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
4061e209fccSTamas Berghammer                 value_to_write.SetType(full_reg_info);
4071e209fccSTamas Berghammer                 reg_to_write = full_reg;
4081e209fccSTamas Berghammer             }
4091e209fccSTamas Berghammer         }
4101e209fccSTamas Berghammer     }
4111e209fccSTamas Berghammer 
4121e209fccSTamas Berghammer     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
4131e209fccSTamas Berghammer     if (!process_sp)
4141e209fccSTamas Berghammer     {
4151e209fccSTamas Berghammer         error.SetErrorString ("NativeProcessProtocol is NULL");
4161e209fccSTamas Berghammer         return error;
4171e209fccSTamas Berghammer     }
4181e209fccSTamas Berghammer 
4191e209fccSTamas Berghammer     const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write);
4201e209fccSTamas Berghammer     assert (register_to_write_info_p && "register to write does not have valid RegisterInfo");
4211e209fccSTamas Berghammer     if (!register_to_write_info_p)
4221e209fccSTamas Berghammer     {
4231e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_arm64::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
4241e209fccSTamas Berghammer         return error;
4251e209fccSTamas Berghammer     }
4261e209fccSTamas Berghammer 
4271e209fccSTamas Berghammer     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
4281e209fccSTamas Berghammer     return process_p->WriteRegisterValue(m_thread.GetID(),
4291e209fccSTamas Berghammer                                          register_to_write_info_p->byte_offset,
4301e209fccSTamas Berghammer                                          register_to_write_info_p->name,
4311e209fccSTamas Berghammer                                          value_to_write);
4321e209fccSTamas Berghammer }
4331e209fccSTamas Berghammer 
434*db264a6dSTamas Berghammer Error
4351e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadRegisterRaw (uint32_t reg_index, RegisterValue &reg_value)
4361e209fccSTamas Berghammer {
4371e209fccSTamas Berghammer     Error error;
4381e209fccSTamas Berghammer     const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index);
4391e209fccSTamas Berghammer     if (!reg_info)
4401e209fccSTamas Berghammer     {
4411e209fccSTamas Berghammer         error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index);
4421e209fccSTamas Berghammer         return error;
4431e209fccSTamas Berghammer     }
4441e209fccSTamas Berghammer 
4451e209fccSTamas Berghammer     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
4461e209fccSTamas Berghammer     if (!process_sp)
4471e209fccSTamas Berghammer     {
4481e209fccSTamas Berghammer         error.SetErrorString ("NativeProcessProtocol is NULL");
4491e209fccSTamas Berghammer         return error;
4501e209fccSTamas Berghammer     }
4511e209fccSTamas Berghammer 
4521e209fccSTamas Berghammer     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
4531e209fccSTamas Berghammer     return process_p->ReadRegisterValue(m_thread.GetID(),
4541e209fccSTamas Berghammer                                         reg_info->byte_offset,
4551e209fccSTamas Berghammer                                         reg_info->name,
4561e209fccSTamas Berghammer                                         reg_info->byte_size,
4571e209fccSTamas Berghammer                                         reg_value);
4581e209fccSTamas Berghammer }
4591e209fccSTamas Berghammer 
4601e209fccSTamas Berghammer bool
4611e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const
4621e209fccSTamas Berghammer {
4631e209fccSTamas Berghammer     return reg <= m_reg_info.last_gpr;   // GPR's come first.
4641e209fccSTamas Berghammer }
4651e209fccSTamas Berghammer 
4661e209fccSTamas Berghammer bool
4671e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadGPR()
4681e209fccSTamas Berghammer {
4691e209fccSTamas Berghammer     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
4701e209fccSTamas Berghammer     if (!process_sp)
4711e209fccSTamas Berghammer         return false;
4721e209fccSTamas Berghammer     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
4731e209fccSTamas Berghammer 
4741e209fccSTamas Berghammer     return process_p->ReadGPR (m_thread.GetID (), &m_gpr_arm64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
4751e209fccSTamas Berghammer }
4761e209fccSTamas Berghammer 
4771e209fccSTamas Berghammer bool
4781e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteGPR()
4791e209fccSTamas Berghammer {
4801e209fccSTamas Berghammer     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
4811e209fccSTamas Berghammer     if (!process_sp)
4821e209fccSTamas Berghammer         return false;
4831e209fccSTamas Berghammer     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
4841e209fccSTamas Berghammer 
4851e209fccSTamas Berghammer     return process_p->WriteGPR (m_thread.GetID (), &m_gpr_arm64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
4861e209fccSTamas Berghammer }
4871e209fccSTamas Berghammer 
4881e209fccSTamas Berghammer bool
4891e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const
4901e209fccSTamas Berghammer {
4911e209fccSTamas Berghammer     return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
4921e209fccSTamas Berghammer }
4931e209fccSTamas Berghammer 
4941e209fccSTamas Berghammer bool
4951e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::ReadFPR ()
4961e209fccSTamas Berghammer {
4971e209fccSTamas Berghammer     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
4981e209fccSTamas Berghammer     if (!process_sp)
4991e209fccSTamas Berghammer         return false;
5001e209fccSTamas Berghammer 
5011e209fccSTamas Berghammer     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
5021e209fccSTamas Berghammer     return process_p->ReadFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
5031e209fccSTamas Berghammer }
5041e209fccSTamas Berghammer 
5051e209fccSTamas Berghammer bool
5061e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::WriteFPR ()
5071e209fccSTamas Berghammer {
5081e209fccSTamas Berghammer     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
5091e209fccSTamas Berghammer     if (!process_sp)
5101e209fccSTamas Berghammer         return false;
5111e209fccSTamas Berghammer 
5121e209fccSTamas Berghammer     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
5131e209fccSTamas Berghammer     return process_p->WriteFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
5141e209fccSTamas Berghammer }
5151e209fccSTamas Berghammer 
5161e209fccSTamas Berghammer lldb::ByteOrder
5171e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetByteOrder() const
5181e209fccSTamas Berghammer {
5191e209fccSTamas Berghammer     // Get the target process whose privileged thread was used for the register read.
5201e209fccSTamas Berghammer     lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
5211e209fccSTamas Berghammer 
5221e209fccSTamas Berghammer     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
5231e209fccSTamas Berghammer     if (!process_sp)
5241e209fccSTamas Berghammer         return byte_order;
5251e209fccSTamas Berghammer 
5261e209fccSTamas Berghammer     if (!process_sp->GetByteOrder (byte_order))
5271e209fccSTamas Berghammer     {
5281e209fccSTamas Berghammer         // FIXME log here
5291e209fccSTamas Berghammer     }
5301e209fccSTamas Berghammer 
5311e209fccSTamas Berghammer     return byte_order;
5321e209fccSTamas Berghammer }
5331e209fccSTamas Berghammer 
5341e209fccSTamas Berghammer size_t
5351e209fccSTamas Berghammer NativeRegisterContextLinux_arm64::GetGPRSize() const
5361e209fccSTamas Berghammer {
5371e209fccSTamas Berghammer     return GetRegisterInfoInterface().GetGPRSize();
5381e209fccSTamas Berghammer }
539