13f57216cSOmair Javaid //===-- NativeRegisterContextLinux_arm.cpp --------------------*- C++ -*-===//
23f57216cSOmair Javaid //
33f57216cSOmair Javaid //                     The LLVM Compiler Infrastructure
43f57216cSOmair Javaid //
53f57216cSOmair Javaid // This file is distributed under the University of Illinois Open Source
63f57216cSOmair Javaid // License. See LICENSE.TXT for details.
73f57216cSOmair Javaid //
83f57216cSOmair Javaid //===----------------------------------------------------------------------===//
93f57216cSOmair Javaid 
10e85e6021STamas Berghammer #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
11068f8a7eSTamas Berghammer 
123f57216cSOmair Javaid #include "NativeRegisterContextLinux_arm.h"
133f57216cSOmair Javaid 
143f57216cSOmair Javaid #include "lldb/Core/RegisterValue.h"
15666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
166f9e6901SZachary Turner #include "lldb/Utility/Log.h"
17*97206d57SZachary Turner #include "lldb/Utility/Status.h"
18068f8a7eSTamas Berghammer 
19e85e6021STamas Berghammer #include "Plugins/Process/Linux/Procfs.h"
20ea1b6b17SPavel Labath #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
214b2b6bfbSPavel Labath #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
223f57216cSOmair Javaid 
23e85e6021STamas Berghammer #include <elf.h>
24e85e6021STamas Berghammer #include <sys/socket.h>
25e85e6021STamas Berghammer 
263f57216cSOmair Javaid #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr))
273f57216cSOmair Javaid 
28ce26b7a6STamas Berghammer #ifndef PTRACE_GETVFPREGS
29ce26b7a6STamas Berghammer #define PTRACE_GETVFPREGS 27
30ce26b7a6STamas Berghammer #define PTRACE_SETVFPREGS 28
31ce26b7a6STamas Berghammer #endif
322441aecdSOmair Javaid #ifndef PTRACE_GETHBPREGS
332441aecdSOmair Javaid #define PTRACE_GETHBPREGS 29
342441aecdSOmair Javaid #define PTRACE_SETHBPREGS 30
352441aecdSOmair Javaid #endif
362441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG3)
372441aecdSOmair Javaid #define PTRACE_TYPE_ARG3 void *
382441aecdSOmair Javaid #endif
392441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG4)
402441aecdSOmair Javaid #define PTRACE_TYPE_ARG4 void *
412441aecdSOmair Javaid #endif
422441aecdSOmair Javaid 
433f57216cSOmair Javaid using namespace lldb;
443f57216cSOmair Javaid using namespace lldb_private;
453f57216cSOmair Javaid using namespace lldb_private::process_linux;
463f57216cSOmair Javaid 
473f57216cSOmair Javaid // arm general purpose registers.
48b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_arm[] = {
49b9c1b51eSKate Stone     gpr_r0_arm,         gpr_r1_arm,   gpr_r2_arm,  gpr_r3_arm, gpr_r4_arm,
50b9c1b51eSKate Stone     gpr_r5_arm,         gpr_r6_arm,   gpr_r7_arm,  gpr_r8_arm, gpr_r9_arm,
51b9c1b51eSKate Stone     gpr_r10_arm,        gpr_r11_arm,  gpr_r12_arm, gpr_sp_arm, gpr_lr_arm,
52b9c1b51eSKate Stone     gpr_pc_arm,         gpr_cpsr_arm,
533f57216cSOmair Javaid     LLDB_INVALID_REGNUM // register sets need to end with this flag
543f57216cSOmair Javaid };
55b9c1b51eSKate Stone static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) ==
56b9c1b51eSKate Stone                   k_num_gpr_registers_arm,
573f57216cSOmair Javaid               "g_gpr_regnums_arm has wrong number of register infos");
583f57216cSOmair Javaid 
593f57216cSOmair Javaid // arm floating point registers.
60b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_arm[] = {
61b9c1b51eSKate Stone     fpu_s0_arm,         fpu_s1_arm,  fpu_s2_arm,    fpu_s3_arm,  fpu_s4_arm,
62b9c1b51eSKate Stone     fpu_s5_arm,         fpu_s6_arm,  fpu_s7_arm,    fpu_s8_arm,  fpu_s9_arm,
63b9c1b51eSKate Stone     fpu_s10_arm,        fpu_s11_arm, fpu_s12_arm,   fpu_s13_arm, fpu_s14_arm,
64b9c1b51eSKate Stone     fpu_s15_arm,        fpu_s16_arm, fpu_s17_arm,   fpu_s18_arm, fpu_s19_arm,
65b9c1b51eSKate Stone     fpu_s20_arm,        fpu_s21_arm, fpu_s22_arm,   fpu_s23_arm, fpu_s24_arm,
66b9c1b51eSKate Stone     fpu_s25_arm,        fpu_s26_arm, fpu_s27_arm,   fpu_s28_arm, fpu_s29_arm,
67b9c1b51eSKate Stone     fpu_s30_arm,        fpu_s31_arm, fpu_fpscr_arm, fpu_d0_arm,  fpu_d1_arm,
68b9c1b51eSKate Stone     fpu_d2_arm,         fpu_d3_arm,  fpu_d4_arm,    fpu_d5_arm,  fpu_d6_arm,
69b9c1b51eSKate Stone     fpu_d7_arm,         fpu_d8_arm,  fpu_d9_arm,    fpu_d10_arm, fpu_d11_arm,
70b9c1b51eSKate Stone     fpu_d12_arm,        fpu_d13_arm, fpu_d14_arm,   fpu_d15_arm, fpu_d16_arm,
71b9c1b51eSKate Stone     fpu_d17_arm,        fpu_d18_arm, fpu_d19_arm,   fpu_d20_arm, fpu_d21_arm,
72b9c1b51eSKate Stone     fpu_d22_arm,        fpu_d23_arm, fpu_d24_arm,   fpu_d25_arm, fpu_d26_arm,
73b9c1b51eSKate Stone     fpu_d27_arm,        fpu_d28_arm, fpu_d29_arm,   fpu_d30_arm, fpu_d31_arm,
74b9c1b51eSKate Stone     fpu_q0_arm,         fpu_q1_arm,  fpu_q2_arm,    fpu_q3_arm,  fpu_q4_arm,
75b9c1b51eSKate Stone     fpu_q5_arm,         fpu_q6_arm,  fpu_q7_arm,    fpu_q8_arm,  fpu_q9_arm,
76b9c1b51eSKate Stone     fpu_q10_arm,        fpu_q11_arm, fpu_q12_arm,   fpu_q13_arm, fpu_q14_arm,
77b4e95a50STamas Berghammer     fpu_q15_arm,
783f57216cSOmair Javaid     LLDB_INVALID_REGNUM // register sets need to end with this flag
793f57216cSOmair Javaid };
80b9c1b51eSKate Stone static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) ==
81b9c1b51eSKate Stone                   k_num_fpr_registers_arm,
823f57216cSOmair Javaid               "g_fpu_regnums_arm has wrong number of register infos");
833f57216cSOmair Javaid 
843f57216cSOmair Javaid namespace {
853f57216cSOmair Javaid // Number of register sets provided by this context.
86b9c1b51eSKate Stone enum { k_num_register_sets = 2 };
873f57216cSOmair Javaid }
883f57216cSOmair Javaid 
893f57216cSOmair Javaid // Register sets for arm.
90b9c1b51eSKate Stone static const RegisterSet g_reg_sets_arm[k_num_register_sets] = {
91b9c1b51eSKate Stone     {"General Purpose Registers", "gpr", k_num_gpr_registers_arm,
92b9c1b51eSKate Stone      g_gpr_regnums_arm},
93b9c1b51eSKate Stone     {"Floating Point Registers", "fpu", k_num_fpr_registers_arm,
94b9c1b51eSKate Stone      g_fpu_regnums_arm}};
953f57216cSOmair Javaid 
96e85e6021STamas Berghammer #if defined(__arm__)
97e85e6021STamas Berghammer 
98068f8a7eSTamas Berghammer NativeRegisterContextLinux *
99b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
100b9c1b51eSKate Stone     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
101b9c1b51eSKate Stone     uint32_t concrete_frame_idx) {
102b9c1b51eSKate Stone   return new NativeRegisterContextLinux_arm(target_arch, native_thread,
103b9c1b51eSKate Stone                                             concrete_frame_idx);
104068f8a7eSTamas Berghammer }
105068f8a7eSTamas Berghammer 
106e85e6021STamas Berghammer #endif // defined(__arm__)
107e85e6021STamas Berghammer 
108b9c1b51eSKate Stone NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
109b9c1b51eSKate Stone     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
110b9c1b51eSKate Stone     uint32_t concrete_frame_idx)
111b9c1b51eSKate Stone     : NativeRegisterContextLinux(native_thread, concrete_frame_idx,
1124b2b6bfbSPavel Labath                                  new RegisterInfoPOSIX_arm(target_arch)) {
113b9c1b51eSKate Stone   switch (target_arch.GetMachine()) {
1143f57216cSOmair Javaid   case llvm::Triple::arm:
1153f57216cSOmair Javaid     m_reg_info.num_registers = k_num_registers_arm;
1163f57216cSOmair Javaid     m_reg_info.num_gpr_registers = k_num_gpr_registers_arm;
1173f57216cSOmair Javaid     m_reg_info.num_fpr_registers = k_num_fpr_registers_arm;
1183f57216cSOmair Javaid     m_reg_info.last_gpr = k_last_gpr_arm;
1193f57216cSOmair Javaid     m_reg_info.first_fpr = k_first_fpr_arm;
1203f57216cSOmair Javaid     m_reg_info.last_fpr = k_last_fpr_arm;
1213f57216cSOmair Javaid     m_reg_info.first_fpr_v = fpu_s0_arm;
1223f57216cSOmair Javaid     m_reg_info.last_fpr_v = fpu_s31_arm;
1233f57216cSOmair Javaid     m_reg_info.gpr_flags = gpr_cpsr_arm;
1243f57216cSOmair Javaid     break;
1253f57216cSOmair Javaid   default:
1263f57216cSOmair Javaid     assert(false && "Unhandled target architecture.");
1273f57216cSOmair Javaid     break;
1283f57216cSOmair Javaid   }
1293f57216cSOmair Javaid 
1303f57216cSOmair Javaid   ::memset(&m_fpr, 0, sizeof(m_fpr));
1313f57216cSOmair Javaid   ::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm));
1322441aecdSOmair Javaid   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
133d5ffbad2SOmair Javaid   ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs));
1342441aecdSOmair Javaid 
1352441aecdSOmair Javaid   // 16 is just a maximum value, query hardware for actual watchpoint count
1362441aecdSOmair Javaid   m_max_hwp_supported = 16;
1372441aecdSOmair Javaid   m_max_hbp_supported = 16;
1382441aecdSOmair Javaid   m_refresh_hwdebug_info = true;
1393f57216cSOmair Javaid }
1403f57216cSOmair Javaid 
141b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount() const {
1423f57216cSOmair Javaid   return k_num_register_sets;
1433f57216cSOmair Javaid }
1443f57216cSOmair Javaid 
145b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount() const {
1461f149204STamas Berghammer   uint32_t count = 0;
1471f149204STamas Berghammer   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
1481f149204STamas Berghammer     count += g_reg_sets_arm[set_index].num_registers;
1491f149204STamas Berghammer   return count;
1501f149204STamas Berghammer }
1511f149204STamas Berghammer 
1523f57216cSOmair Javaid const RegisterSet *
153b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index) const {
1543f57216cSOmair Javaid   if (set_index < k_num_register_sets)
1553f57216cSOmair Javaid     return &g_reg_sets_arm[set_index];
1563f57216cSOmair Javaid 
1573f57216cSOmair Javaid   return nullptr;
1583f57216cSOmair Javaid }
1593f57216cSOmair Javaid 
160*97206d57SZachary Turner Status
161*97206d57SZachary Turner NativeRegisterContextLinux_arm::ReadRegister(const RegisterInfo *reg_info,
162b9c1b51eSKate Stone                                              RegisterValue &reg_value) {
163*97206d57SZachary Turner   Status error;
1643f57216cSOmair Javaid 
165b9c1b51eSKate Stone   if (!reg_info) {
1663f57216cSOmair Javaid     error.SetErrorString("reg_info NULL");
1673f57216cSOmair Javaid     return error;
1683f57216cSOmair Javaid   }
1693f57216cSOmair Javaid 
1703f57216cSOmair Javaid   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
1713f57216cSOmair Javaid 
172b9c1b51eSKate Stone   if (IsFPR(reg)) {
173068f8a7eSTamas Berghammer     error = ReadFPR();
174068f8a7eSTamas Berghammer     if (error.Fail())
1753f57216cSOmair Javaid       return error;
176b9c1b51eSKate Stone   } else {
1773f57216cSOmair Javaid     uint32_t full_reg = reg;
178b9c1b51eSKate Stone     bool is_subreg = reg_info->invalidate_regs &&
179b9c1b51eSKate Stone                      (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
1803f57216cSOmair Javaid 
181b9c1b51eSKate Stone     if (is_subreg) {
1823f57216cSOmair Javaid       // Read the full aligned 64-bit register.
1833f57216cSOmair Javaid       full_reg = reg_info->invalidate_regs[0];
1843f57216cSOmair Javaid     }
1853f57216cSOmair Javaid 
1863f57216cSOmair Javaid     error = ReadRegisterRaw(full_reg, reg_value);
1873f57216cSOmair Javaid 
188b9c1b51eSKate Stone     if (error.Success()) {
189b9c1b51eSKate Stone       // If our read was not aligned (for ah,bh,ch,dh), shift our returned value
190b9c1b51eSKate Stone       // one byte to the right.
1913f57216cSOmair Javaid       if (is_subreg && (reg_info->byte_offset & 0x1))
1923f57216cSOmair Javaid         reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
1933f57216cSOmair Javaid 
194b9c1b51eSKate Stone       // If our return byte size was greater than the return value reg size,
195b9c1b51eSKate Stone       // then
1963f57216cSOmair Javaid       // use the type specified by reg_info rather than the uint64_t default
1973f57216cSOmair Javaid       if (reg_value.GetByteSize() > reg_info->byte_size)
1983f57216cSOmair Javaid         reg_value.SetType(reg_info);
1993f57216cSOmair Javaid     }
2003f57216cSOmair Javaid     return error;
2013f57216cSOmair Javaid   }
2023f57216cSOmair Javaid 
2033f57216cSOmair Javaid   // Get pointer to m_fpr variable and set the data from it.
204c40e7b17STamas Berghammer   uint32_t fpr_offset = CalculateFprOffset(reg_info);
205c40e7b17STamas Berghammer   assert(fpr_offset < sizeof m_fpr);
206c40e7b17STamas Berghammer   uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
207b9c1b51eSKate Stone   switch (reg_info->byte_size) {
2083f57216cSOmair Javaid   case 2:
2093f57216cSOmair Javaid     reg_value.SetUInt16(*(uint16_t *)src);
2103f57216cSOmair Javaid     break;
2113f57216cSOmair Javaid   case 4:
2123f57216cSOmair Javaid     reg_value.SetUInt32(*(uint32_t *)src);
2133f57216cSOmair Javaid     break;
2143f57216cSOmair Javaid   case 8:
2153f57216cSOmair Javaid     reg_value.SetUInt64(*(uint64_t *)src);
2163f57216cSOmair Javaid     break;
217b4e95a50STamas Berghammer   case 16:
218b4e95a50STamas Berghammer     reg_value.SetBytes(src, 16, GetByteOrder());
219b4e95a50STamas Berghammer     break;
2203f57216cSOmair Javaid   default:
2213f57216cSOmair Javaid     assert(false && "Unhandled data size.");
222b9c1b51eSKate Stone     error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32,
223b9c1b51eSKate Stone                                    reg_info->byte_size);
2243f57216cSOmair Javaid     break;
2253f57216cSOmair Javaid   }
2263f57216cSOmair Javaid 
2273f57216cSOmair Javaid   return error;
2283f57216cSOmair Javaid }
2293f57216cSOmair Javaid 
230*97206d57SZachary Turner Status
231*97206d57SZachary Turner NativeRegisterContextLinux_arm::WriteRegister(const RegisterInfo *reg_info,
232*97206d57SZachary Turner                                               const RegisterValue &reg_value) {
2333f57216cSOmair Javaid   if (!reg_info)
234*97206d57SZachary Turner     return Status("reg_info NULL");
2353f57216cSOmair Javaid 
2363f57216cSOmair Javaid   const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
2373f57216cSOmair Javaid   if (reg_index == LLDB_INVALID_REGNUM)
238*97206d57SZachary Turner     return Status("no lldb regnum for %s", reg_info && reg_info->name
239b9c1b51eSKate Stone                                                ? reg_info->name
240b9c1b51eSKate Stone                                                : "<unknown register>");
2413f57216cSOmair Javaid 
2423f57216cSOmair Javaid   if (IsGPR(reg_index))
2433f57216cSOmair Javaid     return WriteRegisterRaw(reg_index, reg_value);
2443f57216cSOmair Javaid 
245b9c1b51eSKate Stone   if (IsFPR(reg_index)) {
2463f57216cSOmair Javaid     // Get pointer to m_fpr variable and set the data to it.
247c40e7b17STamas Berghammer     uint32_t fpr_offset = CalculateFprOffset(reg_info);
248c40e7b17STamas Berghammer     assert(fpr_offset < sizeof m_fpr);
249c40e7b17STamas Berghammer     uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
250b9c1b51eSKate Stone     switch (reg_info->byte_size) {
2513f57216cSOmair Javaid     case 2:
2523f57216cSOmair Javaid       *(uint16_t *)dst = reg_value.GetAsUInt16();
2533f57216cSOmair Javaid       break;
2543f57216cSOmair Javaid     case 4:
2553f57216cSOmair Javaid       *(uint32_t *)dst = reg_value.GetAsUInt32();
2563f57216cSOmair Javaid       break;
2573f57216cSOmair Javaid     case 8:
2583f57216cSOmair Javaid       *(uint64_t *)dst = reg_value.GetAsUInt64();
2593f57216cSOmair Javaid       break;
2603f57216cSOmair Javaid     default:
2613f57216cSOmair Javaid       assert(false && "Unhandled data size.");
262*97206d57SZachary Turner       return Status("unhandled register data size %" PRIu32,
263b9c1b51eSKate Stone                     reg_info->byte_size);
2643f57216cSOmair Javaid     }
2653f57216cSOmair Javaid 
266*97206d57SZachary Turner     Status error = WriteFPR();
267068f8a7eSTamas Berghammer     if (error.Fail())
268068f8a7eSTamas Berghammer       return error;
2693f57216cSOmair Javaid 
270*97206d57SZachary Turner     return Status();
2713f57216cSOmair Javaid   }
2723f57216cSOmair Javaid 
273*97206d57SZachary Turner   return Status("failed - register wasn't recognized to be a GPR or an FPR, "
274b9c1b51eSKate Stone                 "write strategy unknown");
2753f57216cSOmair Javaid }
2763f57216cSOmair Javaid 
277*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::ReadAllRegisterValues(
278b9c1b51eSKate Stone     lldb::DataBufferSP &data_sp) {
279*97206d57SZachary Turner   Status error;
2803f57216cSOmair Javaid 
2813f57216cSOmair Javaid   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
2823f57216cSOmair Javaid   if (!data_sp)
283*97206d57SZachary Turner     return Status("failed to allocate DataBufferHeap instance of size %" PRIu64,
284b9c1b51eSKate Stone                   (uint64_t)REG_CONTEXT_SIZE);
2853f57216cSOmair Javaid 
286068f8a7eSTamas Berghammer   error = ReadGPR();
287068f8a7eSTamas Berghammer   if (error.Fail())
2883f57216cSOmair Javaid     return error;
2893f57216cSOmair Javaid 
290068f8a7eSTamas Berghammer   error = ReadFPR();
291068f8a7eSTamas Berghammer   if (error.Fail())
2923f57216cSOmair Javaid     return error;
2933f57216cSOmair Javaid 
2943f57216cSOmair Javaid   uint8_t *dst = data_sp->GetBytes();
295b9c1b51eSKate Stone   if (dst == nullptr) {
296b9c1b51eSKate Stone     error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
297b9c1b51eSKate Stone                                    " returned a null pointer",
298b9c1b51eSKate Stone                                    (uint64_t)REG_CONTEXT_SIZE);
2993f57216cSOmair Javaid     return error;
3003f57216cSOmair Javaid   }
3013f57216cSOmair Javaid 
3023f57216cSOmair Javaid   ::memcpy(dst, &m_gpr_arm, GetGPRSize());
3033f57216cSOmair Javaid   dst += GetGPRSize();
3043f57216cSOmair Javaid   ::memcpy(dst, &m_fpr, sizeof(m_fpr));
3053f57216cSOmair Javaid 
3063f57216cSOmair Javaid   return error;
3073f57216cSOmair Javaid }
3083f57216cSOmair Javaid 
309*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::WriteAllRegisterValues(
310b9c1b51eSKate Stone     const lldb::DataBufferSP &data_sp) {
311*97206d57SZachary Turner   Status error;
3123f57216cSOmair Javaid 
313b9c1b51eSKate Stone   if (!data_sp) {
314b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
315b9c1b51eSKate Stone         "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided",
316b9c1b51eSKate Stone         __FUNCTION__);
3173f57216cSOmair Javaid     return error;
3183f57216cSOmair Javaid   }
3193f57216cSOmair Javaid 
320b9c1b51eSKate Stone   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
321b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
322b9c1b51eSKate Stone         "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched "
323b9c1b51eSKate Stone         "data size, expected %" PRIu64 ", actual %" PRIu64,
324b9c1b51eSKate Stone         __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize());
3253f57216cSOmair Javaid     return error;
3263f57216cSOmair Javaid   }
3273f57216cSOmair Javaid 
3283f57216cSOmair Javaid   uint8_t *src = data_sp->GetBytes();
329b9c1b51eSKate Stone   if (src == nullptr) {
330b9c1b51eSKate Stone     error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s "
331b9c1b51eSKate Stone                                    "DataBuffer::GetBytes() returned a null "
332b9c1b51eSKate Stone                                    "pointer",
333b9c1b51eSKate Stone                                    __FUNCTION__);
3343f57216cSOmair Javaid     return error;
3353f57216cSOmair Javaid   }
3363f57216cSOmair Javaid   ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize());
3373f57216cSOmair Javaid 
338068f8a7eSTamas Berghammer   error = WriteGPR();
339068f8a7eSTamas Berghammer   if (error.Fail())
3403f57216cSOmair Javaid     return error;
3413f57216cSOmair Javaid 
3423f57216cSOmair Javaid   src += GetRegisterInfoInterface().GetGPRSize();
3433f57216cSOmair Javaid   ::memcpy(&m_fpr, src, sizeof(m_fpr));
3443f57216cSOmair Javaid 
345068f8a7eSTamas Berghammer   error = WriteFPR();
3463f57216cSOmair Javaid   if (error.Fail())
3473f57216cSOmair Javaid     return error;
3483f57216cSOmair Javaid 
3493f57216cSOmair Javaid   return error;
3503f57216cSOmair Javaid }
3513f57216cSOmair Javaid 
352b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const {
3533f57216cSOmair Javaid   return reg <= m_reg_info.last_gpr; // GPR's come first.
3543f57216cSOmair Javaid }
3553f57216cSOmair Javaid 
356b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const {
3573f57216cSOmair Javaid   return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
3583f57216cSOmair Javaid }
3593f57216cSOmair Javaid 
360d5ffbad2SOmair Javaid uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
361d5ffbad2SOmair Javaid   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
362d5ffbad2SOmair Javaid 
363d5ffbad2SOmair Javaid   if (log)
364d5ffbad2SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
365d5ffbad2SOmair Javaid 
366*97206d57SZachary Turner   Status error;
367d5ffbad2SOmair Javaid 
368d5ffbad2SOmair Javaid   // Read hardware breakpoint and watchpoint information.
369d5ffbad2SOmair Javaid   error = ReadHardwareDebugInfo();
370d5ffbad2SOmair Javaid 
371d5ffbad2SOmair Javaid   if (error.Fail())
372d5ffbad2SOmair Javaid     return 0;
373d5ffbad2SOmair Javaid 
374d5ffbad2SOmair Javaid   LLDB_LOG(log, "{0}", m_max_hbp_supported);
375d5ffbad2SOmair Javaid   return m_max_hbp_supported;
376d5ffbad2SOmair Javaid }
377d5ffbad2SOmair Javaid 
3782441aecdSOmair Javaid uint32_t
379b9c1b51eSKate Stone NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
380b9c1b51eSKate Stone                                                       size_t size) {
381d5ffbad2SOmair Javaid   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
382ea1b6b17SPavel Labath   LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
3832441aecdSOmair Javaid 
3842441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
385*97206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
3862441aecdSOmair Javaid 
3872441aecdSOmair Javaid   if (error.Fail())
3882441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
3892441aecdSOmair Javaid 
3902441aecdSOmair Javaid   uint32_t control_value = 0, bp_index = 0;
3912441aecdSOmair Javaid 
392d5ffbad2SOmair Javaid   // Setup address and control values.
393d5ffbad2SOmair Javaid   // Use size to get a hint of arm vs thumb modes.
394d5ffbad2SOmair Javaid   switch (size) {
395d5ffbad2SOmair Javaid   case 2:
396d5ffbad2SOmair Javaid     control_value = (0x3 << 5) | 7;
397d5ffbad2SOmair Javaid     addr &= ~1;
398d5ffbad2SOmair Javaid     break;
399d5ffbad2SOmair Javaid   case 4:
400d5ffbad2SOmair Javaid     control_value = (0xfu << 5) | 7;
401d5ffbad2SOmair Javaid     addr &= ~3;
402d5ffbad2SOmair Javaid     break;
403d5ffbad2SOmair Javaid   default:
4042441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
405d5ffbad2SOmair Javaid   }
4062441aecdSOmair Javaid 
407d5ffbad2SOmair Javaid   // Iterate over stored breakpoints and find a free bp_index
4082441aecdSOmair Javaid   bp_index = LLDB_INVALID_INDEX32;
409b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
410b9c1b51eSKate Stone     if ((m_hbr_regs[i].control & 1) == 0) {
4112441aecdSOmair Javaid       bp_index = i; // Mark last free slot
412d5ffbad2SOmair Javaid     } else if (m_hbr_regs[i].address == addr) {
413d5ffbad2SOmair Javaid       return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
4142441aecdSOmair Javaid     }
4152441aecdSOmair Javaid   }
4162441aecdSOmair Javaid 
4172441aecdSOmair Javaid   if (bp_index == LLDB_INVALID_INDEX32)
4182441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
4192441aecdSOmair Javaid 
420d5ffbad2SOmair Javaid   // Update breakpoint in local cache
421d5ffbad2SOmair Javaid   m_hbr_regs[bp_index].real_addr = addr;
4222441aecdSOmair Javaid   m_hbr_regs[bp_index].address = addr;
4232441aecdSOmair Javaid   m_hbr_regs[bp_index].control = control_value;
4242441aecdSOmair Javaid 
4252441aecdSOmair Javaid   // PTRACE call to set corresponding hardware breakpoint register.
4262441aecdSOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
4272441aecdSOmair Javaid 
428b9c1b51eSKate Stone   if (error.Fail()) {
429d5510d1eSOmair Javaid     m_hbr_regs[bp_index].address = 0;
430d5510d1eSOmair Javaid     m_hbr_regs[bp_index].control &= ~1;
431d5510d1eSOmair Javaid 
4322441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
4332441aecdSOmair Javaid   }
4342441aecdSOmair Javaid 
4352441aecdSOmair Javaid   return bp_index;
4362441aecdSOmair Javaid }
4372441aecdSOmair Javaid 
438b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
439d5ffbad2SOmair Javaid   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
440ea1b6b17SPavel Labath   LLDB_LOG(log, "hw_idx: {0}", hw_idx);
4412441aecdSOmair Javaid 
4422441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
443*97206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
4442441aecdSOmair Javaid 
4452441aecdSOmair Javaid   if (error.Fail())
4464aa984c1SOmair Javaid     return false;
4472441aecdSOmair Javaid 
4482441aecdSOmair Javaid   if (hw_idx >= m_max_hbp_supported)
4492441aecdSOmair Javaid     return false;
4502441aecdSOmair Javaid 
451d5510d1eSOmair Javaid   // Create a backup we can revert to in case of failure.
452d5510d1eSOmair Javaid   lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
453d5510d1eSOmair Javaid   uint32_t tempControl = m_hbr_regs[hw_idx].control;
454d5510d1eSOmair Javaid 
4552441aecdSOmair Javaid   m_hbr_regs[hw_idx].control &= ~1;
4562441aecdSOmair Javaid   m_hbr_regs[hw_idx].address = 0;
4572441aecdSOmair Javaid 
4582441aecdSOmair Javaid   // PTRACE call to clear corresponding hardware breakpoint register.
459d5ffbad2SOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
4602441aecdSOmair Javaid 
461b9c1b51eSKate Stone   if (error.Fail()) {
462d5510d1eSOmair Javaid     m_hbr_regs[hw_idx].control = tempControl;
463d5510d1eSOmair Javaid     m_hbr_regs[hw_idx].address = tempAddr;
464d5510d1eSOmair Javaid 
4654aa984c1SOmair Javaid     return false;
466d5510d1eSOmair Javaid   }
4672441aecdSOmair Javaid 
4682441aecdSOmair Javaid   return true;
4692441aecdSOmair Javaid }
4702441aecdSOmair Javaid 
471*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
472d5ffbad2SOmair Javaid     uint32_t &bp_index, lldb::addr_t trap_addr) {
473d5ffbad2SOmair Javaid   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
474d5ffbad2SOmair Javaid 
475d5ffbad2SOmair Javaid   if (log)
476d5ffbad2SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
477d5ffbad2SOmair Javaid 
478d5ffbad2SOmair Javaid   lldb::addr_t break_addr;
479d5ffbad2SOmair Javaid 
480d5ffbad2SOmair Javaid   for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
481d5ffbad2SOmair Javaid     break_addr = m_hbr_regs[bp_index].address;
482d5ffbad2SOmair Javaid 
483d5ffbad2SOmair Javaid     if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
484d5ffbad2SOmair Javaid       m_hbr_regs[bp_index].hit_addr = trap_addr;
485*97206d57SZachary Turner       return Status();
486d5ffbad2SOmair Javaid     }
487d5ffbad2SOmair Javaid   }
488d5ffbad2SOmair Javaid 
489d5ffbad2SOmair Javaid   bp_index = LLDB_INVALID_INDEX32;
490*97206d57SZachary Turner   return Status();
491d5ffbad2SOmair Javaid }
492d5ffbad2SOmair Javaid 
493*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
494d5ffbad2SOmair Javaid   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
495d5ffbad2SOmair Javaid 
496d5ffbad2SOmair Javaid   if (log)
497d5ffbad2SOmair Javaid     log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
498d5ffbad2SOmair Javaid 
499*97206d57SZachary Turner   Status error;
500d5ffbad2SOmair Javaid 
501d5ffbad2SOmair Javaid   // Read hardware breakpoint and watchpoint information.
502d5ffbad2SOmair Javaid   error = ReadHardwareDebugInfo();
503d5ffbad2SOmair Javaid 
504d5ffbad2SOmair Javaid   if (error.Fail())
505d5ffbad2SOmair Javaid     return error;
506d5ffbad2SOmair Javaid 
507d5ffbad2SOmair Javaid   lldb::addr_t tempAddr = 0;
508d5ffbad2SOmair Javaid   uint32_t tempControl = 0;
509d5ffbad2SOmair Javaid 
510d5ffbad2SOmair Javaid   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
511d5ffbad2SOmair Javaid     if (m_hbr_regs[i].control & 0x01) {
512d5ffbad2SOmair Javaid       // Create a backup we can revert to in case of failure.
513d5ffbad2SOmair Javaid       tempAddr = m_hbr_regs[i].address;
514d5ffbad2SOmair Javaid       tempControl = m_hbr_regs[i].control;
515d5ffbad2SOmair Javaid 
516d5ffbad2SOmair Javaid       // Clear breakpoints in local cache
517d5ffbad2SOmair Javaid       m_hbr_regs[i].control &= ~1;
518d5ffbad2SOmair Javaid       m_hbr_regs[i].address = 0;
519d5ffbad2SOmair Javaid 
520d5ffbad2SOmair Javaid       // Ptrace call to update hardware debug registers
521d5ffbad2SOmair Javaid       error = WriteHardwareDebugRegs(eDREGTypeBREAK, i);
522d5ffbad2SOmair Javaid 
523d5ffbad2SOmair Javaid       if (error.Fail()) {
524d5ffbad2SOmair Javaid         m_hbr_regs[i].control = tempControl;
525d5ffbad2SOmair Javaid         m_hbr_regs[i].address = tempAddr;
526d5ffbad2SOmair Javaid 
527d5ffbad2SOmair Javaid         return error;
528d5ffbad2SOmair Javaid       }
529d5ffbad2SOmair Javaid     }
530d5ffbad2SOmair Javaid   }
531d5ffbad2SOmair Javaid 
532*97206d57SZachary Turner   return Status();
5332441aecdSOmair Javaid }
5342441aecdSOmair Javaid 
535b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
536ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
5372441aecdSOmair Javaid 
5382441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
539*97206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
5402441aecdSOmair Javaid 
5412441aecdSOmair Javaid   if (error.Fail())
54262661473SOmair Javaid     return 0;
5432441aecdSOmair Javaid 
544ea1b6b17SPavel Labath   LLDB_LOG(log, "{0}", m_max_hwp_supported);
5452441aecdSOmair Javaid   return m_max_hwp_supported;
5462441aecdSOmair Javaid }
5472441aecdSOmair Javaid 
548b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
549b9c1b51eSKate Stone     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
550ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
551ea1b6b17SPavel Labath   LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
552ea1b6b17SPavel Labath            watch_flags);
5532441aecdSOmair Javaid 
5542441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
555*97206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
5562441aecdSOmair Javaid 
5572441aecdSOmair Javaid   if (error.Fail())
5582441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5592441aecdSOmair Javaid 
5602441aecdSOmair Javaid   uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
561c6dc90efSOmair Javaid   lldb::addr_t real_addr = addr;
5622441aecdSOmair Javaid 
5632441aecdSOmair Javaid   // Check if we are setting watchpoint other than read/write/access
5642441aecdSOmair Javaid   // Also update watchpoint flag to match Arm write-read bit configuration.
565b9c1b51eSKate Stone   switch (watch_flags) {
5662441aecdSOmair Javaid   case 1:
5672441aecdSOmair Javaid     watch_flags = 2;
5682441aecdSOmair Javaid     break;
5692441aecdSOmair Javaid   case 2:
5702441aecdSOmair Javaid     watch_flags = 1;
5712441aecdSOmair Javaid     break;
5722441aecdSOmair Javaid   case 3:
5732441aecdSOmair Javaid     break;
5742441aecdSOmair Javaid   default:
5752441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5762441aecdSOmair Javaid   }
5772441aecdSOmair Javaid 
5782441aecdSOmair Javaid   // Can't watch zero bytes
5792441aecdSOmair Javaid   // Can't watch more than 4 bytes per WVR/WCR pair
5802441aecdSOmair Javaid 
5812441aecdSOmair Javaid   if (size == 0 || size > 4)
5822441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5832441aecdSOmair Javaid 
584c6dc90efSOmair Javaid   // Check 4-byte alignment for hardware watchpoint target address.
585c6dc90efSOmair Javaid   // Below is a hack to recalculate address and size in order to
586c6dc90efSOmair Javaid   // make sure we can watch non 4-byte alligned addresses as well.
587b9c1b51eSKate Stone   if (addr & 0x03) {
588c6dc90efSOmair Javaid     uint8_t watch_mask = (addr & 0x03) + size;
589c6dc90efSOmair Javaid 
590c6dc90efSOmair Javaid     if (watch_mask > 0x04)
591c6dc90efSOmair Javaid       return LLDB_INVALID_INDEX32;
592c6dc90efSOmair Javaid     else if (watch_mask <= 0x02)
593c6dc90efSOmair Javaid       size = 2;
594c6dc90efSOmair Javaid     else if (watch_mask <= 0x04)
595c6dc90efSOmair Javaid       size = 4;
596c6dc90efSOmair Javaid 
597c6dc90efSOmair Javaid     addr = addr & (~0x03);
598c6dc90efSOmair Javaid   }
599c6dc90efSOmair Javaid 
6002441aecdSOmair Javaid   // We can only watch up to four bytes that follow a 4 byte aligned address
6012441aecdSOmair Javaid   // per watchpoint register pair, so make sure we can properly encode this.
6022441aecdSOmair Javaid   addr_word_offset = addr % 4;
6032441aecdSOmair Javaid   byte_mask = ((1u << size) - 1u) << addr_word_offset;
6042441aecdSOmair Javaid 
6052441aecdSOmair Javaid   // Check if we need multiple watchpoint register
6062441aecdSOmair Javaid   if (byte_mask > 0xfu)
6072441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
6082441aecdSOmair Javaid 
6092441aecdSOmair Javaid   // Setup control value
6102441aecdSOmair Javaid   // Make the byte_mask into a valid Byte Address Select mask
6112441aecdSOmair Javaid   control_value = byte_mask << 5;
6122441aecdSOmair Javaid 
6132441aecdSOmair Javaid   // Turn on appropriate watchpoint flags read or write
6142441aecdSOmair Javaid   control_value |= (watch_flags << 3);
6152441aecdSOmair Javaid 
6162441aecdSOmair Javaid   // Enable this watchpoint and make it stop in privileged or user mode;
6172441aecdSOmair Javaid   control_value |= 7;
6182441aecdSOmair Javaid 
6192441aecdSOmair Javaid   // Make sure bits 1:0 are clear in our address
6202441aecdSOmair Javaid   addr &= ~((lldb::addr_t)3);
6212441aecdSOmair Javaid 
62205ac4c44SOmair Javaid   // Iterate over stored watchpoints and find a free wp_index
6232441aecdSOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
624b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
625b9c1b51eSKate Stone     if ((m_hwp_regs[i].control & 1) == 0) {
6262441aecdSOmair Javaid       wp_index = i; // Mark last free slot
62705ac4c44SOmair Javaid     } else if (m_hwp_regs[i].address == addr) {
62805ac4c44SOmair Javaid       return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
6292441aecdSOmair Javaid     }
6302441aecdSOmair Javaid   }
6312441aecdSOmair Javaid 
6322441aecdSOmair Javaid   if (wp_index == LLDB_INVALID_INDEX32)
6332441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
6342441aecdSOmair Javaid 
6352441aecdSOmair Javaid   // Update watchpoint in local cache
636c6dc90efSOmair Javaid   m_hwp_regs[wp_index].real_addr = real_addr;
6372441aecdSOmair Javaid   m_hwp_regs[wp_index].address = addr;
6382441aecdSOmair Javaid   m_hwp_regs[wp_index].control = control_value;
6392441aecdSOmair Javaid 
6402441aecdSOmair Javaid   // PTRACE call to set corresponding watchpoint register.
6412441aecdSOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
6422441aecdSOmair Javaid 
643b9c1b51eSKate Stone   if (error.Fail()) {
644d5510d1eSOmair Javaid     m_hwp_regs[wp_index].address = 0;
645d5510d1eSOmair Javaid     m_hwp_regs[wp_index].control &= ~1;
646d5510d1eSOmair Javaid 
6472441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
6482441aecdSOmair Javaid   }
6492441aecdSOmair Javaid 
6502441aecdSOmair Javaid   return wp_index;
6512441aecdSOmair Javaid }
6522441aecdSOmair Javaid 
653b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
654b9c1b51eSKate Stone     uint32_t wp_index) {
655ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
656ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
6572441aecdSOmair Javaid 
6582441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
659*97206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
6602441aecdSOmair Javaid 
6612441aecdSOmair Javaid   if (error.Fail())
6624aa984c1SOmair Javaid     return false;
6632441aecdSOmair Javaid 
6642441aecdSOmair Javaid   if (wp_index >= m_max_hwp_supported)
6652441aecdSOmair Javaid     return false;
6662441aecdSOmair Javaid 
667d5510d1eSOmair Javaid   // Create a backup we can revert to in case of failure.
668d5510d1eSOmair Javaid   lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
669d5510d1eSOmair Javaid   uint32_t tempControl = m_hwp_regs[wp_index].control;
670d5510d1eSOmair Javaid 
6712441aecdSOmair Javaid   // Update watchpoint in local cache
6722441aecdSOmair Javaid   m_hwp_regs[wp_index].control &= ~1;
6732441aecdSOmair Javaid   m_hwp_regs[wp_index].address = 0;
6742441aecdSOmair Javaid 
6752441aecdSOmair Javaid   // Ptrace call to update hardware debug registers
6762441aecdSOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
6772441aecdSOmair Javaid 
678b9c1b51eSKate Stone   if (error.Fail()) {
679d5510d1eSOmair Javaid     m_hwp_regs[wp_index].control = tempControl;
680d5510d1eSOmair Javaid     m_hwp_regs[wp_index].address = tempAddr;
681d5510d1eSOmair Javaid 
6822441aecdSOmair Javaid     return false;
683d5510d1eSOmair Javaid   }
6842441aecdSOmair Javaid 
6852441aecdSOmair Javaid   return true;
6862441aecdSOmair Javaid }
6872441aecdSOmair Javaid 
688*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
6892441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
690*97206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
6912441aecdSOmair Javaid 
6922441aecdSOmair Javaid   if (error.Fail())
6932441aecdSOmair Javaid     return error;
6942441aecdSOmair Javaid 
695d5510d1eSOmair Javaid   lldb::addr_t tempAddr = 0;
69605ac4c44SOmair Javaid   uint32_t tempControl = 0;
697d5510d1eSOmair Javaid 
698b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
699b9c1b51eSKate Stone     if (m_hwp_regs[i].control & 0x01) {
700d5510d1eSOmair Javaid       // Create a backup we can revert to in case of failure.
701d5510d1eSOmair Javaid       tempAddr = m_hwp_regs[i].address;
702d5510d1eSOmair Javaid       tempControl = m_hwp_regs[i].control;
703d5510d1eSOmair Javaid 
7042441aecdSOmair Javaid       // Clear watchpoints in local cache
7052441aecdSOmair Javaid       m_hwp_regs[i].control &= ~1;
7062441aecdSOmair Javaid       m_hwp_regs[i].address = 0;
7072441aecdSOmair Javaid 
7082441aecdSOmair Javaid       // Ptrace call to update hardware debug registers
7092441aecdSOmair Javaid       error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
7102441aecdSOmair Javaid 
711b9c1b51eSKate Stone       if (error.Fail()) {
712d5510d1eSOmair Javaid         m_hwp_regs[i].control = tempControl;
713d5510d1eSOmair Javaid         m_hwp_regs[i].address = tempAddr;
714d5510d1eSOmair Javaid 
7152441aecdSOmair Javaid         return error;
7162441aecdSOmair Javaid       }
7172441aecdSOmair Javaid     }
718d5510d1eSOmair Javaid   }
7192441aecdSOmair Javaid 
720*97206d57SZachary Turner   return Status();
7212441aecdSOmair Javaid }
7222441aecdSOmair Javaid 
723b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) {
724ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
725ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
7262441aecdSOmair Javaid 
727b9c1b51eSKate Stone   switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
7282441aecdSOmair Javaid   case 0x01:
7292441aecdSOmair Javaid     return 1;
7302441aecdSOmair Javaid   case 0x03:
7312441aecdSOmair Javaid     return 2;
7322441aecdSOmair Javaid   case 0x07:
7332441aecdSOmair Javaid     return 3;
7342441aecdSOmair Javaid   case 0x0f:
7352441aecdSOmair Javaid     return 4;
7362441aecdSOmair Javaid   default:
7372441aecdSOmair Javaid     return 0;
7382441aecdSOmair Javaid   }
7392441aecdSOmair Javaid }
740b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) {
741ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
742ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
7432441aecdSOmair Javaid 
7442441aecdSOmair Javaid   if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
7452441aecdSOmair Javaid     return true;
7462441aecdSOmair Javaid   else
7472441aecdSOmair Javaid     return false;
7482441aecdSOmair Javaid }
7492441aecdSOmair Javaid 
750*97206d57SZachary Turner Status
751*97206d57SZachary Turner NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index,
752*97206d57SZachary Turner                                                       lldb::addr_t trap_addr) {
753ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
754ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
7552441aecdSOmair Javaid 
7562441aecdSOmair Javaid   uint32_t watch_size;
7572441aecdSOmair Javaid   lldb::addr_t watch_addr;
7582441aecdSOmair Javaid 
759b9c1b51eSKate Stone   for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
7602441aecdSOmair Javaid     watch_size = GetWatchpointSize(wp_index);
7612441aecdSOmair Javaid     watch_addr = m_hwp_regs[wp_index].address;
7622441aecdSOmair Javaid 
76305ac4c44SOmair Javaid     if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
76405ac4c44SOmair Javaid         trap_addr < watch_addr + watch_size) {
765c6dc90efSOmair Javaid       m_hwp_regs[wp_index].hit_addr = trap_addr;
766*97206d57SZachary Turner       return Status();
7672441aecdSOmair Javaid     }
7682441aecdSOmair Javaid   }
7692441aecdSOmair Javaid 
7702441aecdSOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
771*97206d57SZachary Turner   return Status();
7722441aecdSOmair Javaid }
7732441aecdSOmair Javaid 
7742441aecdSOmair Javaid lldb::addr_t
775b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) {
776ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
777ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
7782441aecdSOmair Javaid 
7792441aecdSOmair Javaid   if (wp_index >= m_max_hwp_supported)
7802441aecdSOmair Javaid     return LLDB_INVALID_ADDRESS;
7812441aecdSOmair Javaid 
7822441aecdSOmair Javaid   if (WatchpointIsEnabled(wp_index))
783c6dc90efSOmair Javaid     return m_hwp_regs[wp_index].real_addr;
784c6dc90efSOmair Javaid   else
785c6dc90efSOmair Javaid     return LLDB_INVALID_ADDRESS;
786c6dc90efSOmair Javaid }
787c6dc90efSOmair Javaid 
788c6dc90efSOmair Javaid lldb::addr_t
789b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) {
790ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
791ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
792c6dc90efSOmair Javaid 
793c6dc90efSOmair Javaid   if (wp_index >= m_max_hwp_supported)
794c6dc90efSOmair Javaid     return LLDB_INVALID_ADDRESS;
795c6dc90efSOmair Javaid 
796c6dc90efSOmair Javaid   if (WatchpointIsEnabled(wp_index))
797c6dc90efSOmair Javaid     return m_hwp_regs[wp_index].hit_addr;
7982441aecdSOmair Javaid   else
7992441aecdSOmair Javaid     return LLDB_INVALID_ADDRESS;
8002441aecdSOmair Javaid }
8012441aecdSOmair Javaid 
802*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
803*97206d57SZachary Turner   Status error;
8042441aecdSOmair Javaid 
805b9c1b51eSKate Stone   if (!m_refresh_hwdebug_info) {
806*97206d57SZachary Turner     return Status();
8072441aecdSOmair Javaid   }
8082441aecdSOmair Javaid 
8092441aecdSOmair Javaid   unsigned int cap_val;
8102441aecdSOmair Javaid 
811b9c1b51eSKate Stone   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(),
812b9c1b51eSKate Stone                                             nullptr, &cap_val,
813b9c1b51eSKate Stone                                             sizeof(unsigned int));
8142441aecdSOmair Javaid 
8152441aecdSOmair Javaid   if (error.Fail())
8162441aecdSOmair Javaid     return error;
8172441aecdSOmair Javaid 
8182441aecdSOmair Javaid   m_max_hwp_supported = (cap_val >> 8) & 0xff;
8192441aecdSOmair Javaid   m_max_hbp_supported = cap_val & 0xff;
8202441aecdSOmair Javaid   m_refresh_hwdebug_info = false;
8212441aecdSOmair Javaid 
8222441aecdSOmair Javaid   return error;
8232441aecdSOmair Javaid }
8242441aecdSOmair Javaid 
825*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType,
826b9c1b51eSKate Stone                                                               int hwb_index) {
827*97206d57SZachary Turner   Status error;
8282441aecdSOmair Javaid 
8292441aecdSOmair Javaid   lldb::addr_t *addr_buf;
8302441aecdSOmair Javaid   uint32_t *ctrl_buf;
8312441aecdSOmair Javaid 
832b9c1b51eSKate Stone   if (hwbType == eDREGTypeWATCH) {
8332441aecdSOmair Javaid     addr_buf = &m_hwp_regs[hwb_index].address;
8342441aecdSOmair Javaid     ctrl_buf = &m_hwp_regs[hwb_index].control;
8352441aecdSOmair Javaid 
836b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
837b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
838b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf,
839b9c1b51eSKate Stone         sizeof(unsigned int));
8402441aecdSOmair Javaid 
8412441aecdSOmair Javaid     if (error.Fail())
8422441aecdSOmair Javaid       return error;
8432441aecdSOmair Javaid 
844b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
845b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
846b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
847b9c1b51eSKate Stone         sizeof(unsigned int));
848b9c1b51eSKate Stone   } else {
849d5ffbad2SOmair Javaid     addr_buf = &m_hbr_regs[hwb_index].address;
850d5ffbad2SOmair Javaid     ctrl_buf = &m_hbr_regs[hwb_index].control;
8512441aecdSOmair Javaid 
852b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
853b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
854b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf,
855b9c1b51eSKate Stone         sizeof(unsigned int));
8562441aecdSOmair Javaid 
8572441aecdSOmair Javaid     if (error.Fail())
8582441aecdSOmair Javaid       return error;
8592441aecdSOmair Javaid 
860b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
861b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
862b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
863b9c1b51eSKate Stone         sizeof(unsigned int));
8642441aecdSOmair Javaid   }
8652441aecdSOmair Javaid 
8662441aecdSOmair Javaid   return error;
8672441aecdSOmair Javaid }
868c40e7b17STamas Berghammer 
869b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
870b9c1b51eSKate Stone     const RegisterInfo *reg_info) const {
871b9c1b51eSKate Stone   return reg_info->byte_offset -
872b9c1b51eSKate Stone          GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
873c40e7b17STamas Berghammer }
874c40e7b17STamas Berghammer 
875*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoReadRegisterValue(
876b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, uint32_t size,
877b9c1b51eSKate Stone     RegisterValue &value) {
878b9c1b51eSKate Stone   // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android
879b9c1b51eSKate Stone   // devices (always return
880b9c1b51eSKate Stone   // "Bad address"). To avoid using PTRACE_PEEKUSER we read out the full GPR
881b9c1b51eSKate Stone   // register set instead.
882b9c1b51eSKate Stone   // This approach is about 4 times slower but the performance overhead is
883b9c1b51eSKate Stone   // negligible in
884e85e6021STamas Berghammer   // comparision to processing time in lldb-server.
885e85e6021STamas Berghammer   assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
886e85e6021STamas Berghammer   if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
887*97206d57SZachary Turner     return Status("Register isn't fit into the size of the GPR area");
888e85e6021STamas Berghammer 
889*97206d57SZachary Turner   Status error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm));
890e85e6021STamas Berghammer   if (error.Fail())
891e85e6021STamas Berghammer     return error;
892e85e6021STamas Berghammer 
893e85e6021STamas Berghammer   value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]);
894*97206d57SZachary Turner   return Status();
895e85e6021STamas Berghammer }
896e85e6021STamas Berghammer 
897*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoWriteRegisterValue(
898b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, const RegisterValue &value) {
899b9c1b51eSKate Stone   // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android
900b9c1b51eSKate Stone   // devices (always return
901b9c1b51eSKate Stone   // "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR
902b9c1b51eSKate Stone   // register set, modify
903b9c1b51eSKate Stone   // the requested register and write it back. This approach is about 4 times
904b9c1b51eSKate Stone   // slower but the
905b9c1b51eSKate Stone   // performance overhead is negligible in comparision to processing time in
906b9c1b51eSKate Stone   // lldb-server.
907ce26b7a6STamas Berghammer   assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
908ce26b7a6STamas Berghammer   if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
909*97206d57SZachary Turner     return Status("Register isn't fit into the size of the GPR area");
910ce26b7a6STamas Berghammer 
911*97206d57SZachary Turner   Status error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm));
912ce26b7a6STamas Berghammer   if (error.Fail())
913ce26b7a6STamas Berghammer     return error;
914ce26b7a6STamas Berghammer 
915a7d7f7cfSOmair Javaid   uint32_t reg_value = value.GetAsUInt32();
916a7d7f7cfSOmair Javaid   // As precaution for an undefined behavior encountered while setting PC we
917a7d7f7cfSOmair Javaid   // will clear thumb bit of new PC if we are already in thumb mode; that is
918a7d7f7cfSOmair Javaid   // CPSR thumb mode bit is set.
919b9c1b51eSKate Stone   if (offset / sizeof(uint32_t) == gpr_pc_arm) {
920a7d7f7cfSOmair Javaid     // Check if we are already in thumb mode and
921a7d7f7cfSOmair Javaid     // thumb bit of current PC is read out to be zero and
922a7d7f7cfSOmair Javaid     // thumb bit of next PC is read out to be one.
923b9c1b51eSKate Stone     if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) &&
924b9c1b51eSKate Stone         (value.GetAsUInt32() & 0x01)) {
925a7d7f7cfSOmair Javaid       reg_value &= (~1ull);
926a7d7f7cfSOmair Javaid     }
927a7d7f7cfSOmair Javaid   }
928a7d7f7cfSOmair Javaid 
929a7d7f7cfSOmair Javaid   m_gpr_arm[offset / sizeof(uint32_t)] = reg_value;
930ce26b7a6STamas Berghammer   return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm));
931ce26b7a6STamas Berghammer }
932ce26b7a6STamas Berghammer 
933*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoReadGPR(void *buf, size_t buf_size) {
934e85e6021STamas Berghammer #ifdef __arm__
935e85e6021STamas Berghammer   return NativeRegisterContextLinux::DoReadGPR(buf, buf_size);
936e85e6021STamas Berghammer #else  // __aarch64__
937e85e6021STamas Berghammer   struct iovec ioVec;
938e85e6021STamas Berghammer   ioVec.iov_base = buf;
939e85e6021STamas Berghammer   ioVec.iov_len = buf_size;
940e85e6021STamas Berghammer 
941e85e6021STamas Berghammer   return ReadRegisterSet(&ioVec, buf_size, NT_PRSTATUS);
942e85e6021STamas Berghammer #endif // __arm__
943e85e6021STamas Berghammer }
944e85e6021STamas Berghammer 
945*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoWriteGPR(void *buf, size_t buf_size) {
946e85e6021STamas Berghammer #ifdef __arm__
947e85e6021STamas Berghammer   return NativeRegisterContextLinux::DoWriteGPR(buf, buf_size);
948e85e6021STamas Berghammer #else  // __aarch64__
949e85e6021STamas Berghammer   struct iovec ioVec;
950e85e6021STamas Berghammer   ioVec.iov_base = buf;
951e85e6021STamas Berghammer   ioVec.iov_len = buf_size;
952e85e6021STamas Berghammer 
953e85e6021STamas Berghammer   return WriteRegisterSet(&ioVec, buf_size, NT_PRSTATUS);
954e85e6021STamas Berghammer #endif // __arm__
955e85e6021STamas Berghammer }
956e85e6021STamas Berghammer 
957*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size) {
958e85e6021STamas Berghammer #ifdef __arm__
959b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(),
960b9c1b51eSKate Stone                                            nullptr, buf, buf_size);
961e85e6021STamas Berghammer #else  // __aarch64__
962e85e6021STamas Berghammer   struct iovec ioVec;
963e85e6021STamas Berghammer   ioVec.iov_base = buf;
964e85e6021STamas Berghammer   ioVec.iov_len = buf_size;
965e85e6021STamas Berghammer 
966e85e6021STamas Berghammer   return ReadRegisterSet(&ioVec, buf_size, NT_ARM_VFP);
967e85e6021STamas Berghammer #endif // __arm__
968ce26b7a6STamas Berghammer }
969ce26b7a6STamas Berghammer 
970*97206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size) {
971e85e6021STamas Berghammer #ifdef __arm__
972b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(),
973b9c1b51eSKate Stone                                            nullptr, buf, buf_size);
974e85e6021STamas Berghammer #else  // __aarch64__
975e85e6021STamas Berghammer   struct iovec ioVec;
976e85e6021STamas Berghammer   ioVec.iov_base = buf;
977e85e6021STamas Berghammer   ioVec.iov_len = buf_size;
978e85e6021STamas Berghammer 
979e85e6021STamas Berghammer   return WriteRegisterSet(&ioVec, buf_size, NT_ARM_VFP);
980e85e6021STamas Berghammer #endif // __arm__
981ce26b7a6STamas Berghammer }
982ce26b7a6STamas Berghammer 
983e85e6021STamas Berghammer #endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
984