1 //===-- NativeRegisterContextLinux_arm64.cpp --------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #if defined(__arm64__) || defined(__aarch64__)
11 
12 #include "NativeRegisterContextLinux_arm.h"
13 #include "NativeRegisterContextLinux_arm64.h"
14 
15 // C Includes
16 // C++ Includes
17 
18 // Other libraries and framework includes
19 #include "lldb/Core/DataBufferHeap.h"
20 #include "lldb/Core/Log.h"
21 #include "lldb/Core/RegisterValue.h"
22 #include "lldb/Host/common/NativeProcessProtocol.h"
23 #include "lldb/Utility/Error.h"
24 
25 #include "Plugins/Process/Linux/NativeProcessLinux.h"
26 #include "Plugins/Process/Linux/Procfs.h"
27 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
28 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
29 
30 // System includes - They have to be included after framework includes because
31 // they define some
32 // macros which collide with variable names in other modules
33 #include <sys/socket.h>
34 // NT_PRSTATUS and NT_FPREGSET definition
35 #include <elf.h>
36 // user_hwdebug_state definition
37 #include <asm/ptrace.h>
38 
39 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
40 
41 using namespace lldb;
42 using namespace lldb_private;
43 using namespace lldb_private::process_linux;
44 
45 // ARM64 general purpose registers.
46 static const uint32_t g_gpr_regnums_arm64[] = {
47     gpr_x0_arm64,       gpr_x1_arm64,   gpr_x2_arm64,  gpr_x3_arm64,
48     gpr_x4_arm64,       gpr_x5_arm64,   gpr_x6_arm64,  gpr_x7_arm64,
49     gpr_x8_arm64,       gpr_x9_arm64,   gpr_x10_arm64, gpr_x11_arm64,
50     gpr_x12_arm64,      gpr_x13_arm64,  gpr_x14_arm64, gpr_x15_arm64,
51     gpr_x16_arm64,      gpr_x17_arm64,  gpr_x18_arm64, gpr_x19_arm64,
52     gpr_x20_arm64,      gpr_x21_arm64,  gpr_x22_arm64, gpr_x23_arm64,
53     gpr_x24_arm64,      gpr_x25_arm64,  gpr_x26_arm64, gpr_x27_arm64,
54     gpr_x28_arm64,      gpr_fp_arm64,   gpr_lr_arm64,  gpr_sp_arm64,
55     gpr_pc_arm64,       gpr_cpsr_arm64, gpr_w0_arm64,  gpr_w1_arm64,
56     gpr_w2_arm64,       gpr_w3_arm64,   gpr_w4_arm64,  gpr_w5_arm64,
57     gpr_w6_arm64,       gpr_w7_arm64,   gpr_w8_arm64,  gpr_w9_arm64,
58     gpr_w10_arm64,      gpr_w11_arm64,  gpr_w12_arm64, gpr_w13_arm64,
59     gpr_w14_arm64,      gpr_w15_arm64,  gpr_w16_arm64, gpr_w17_arm64,
60     gpr_w18_arm64,      gpr_w19_arm64,  gpr_w20_arm64, gpr_w21_arm64,
61     gpr_w22_arm64,      gpr_w23_arm64,  gpr_w24_arm64, gpr_w25_arm64,
62     gpr_w26_arm64,      gpr_w27_arm64,  gpr_w28_arm64,
63     LLDB_INVALID_REGNUM // register sets need to end with this flag
64 };
65 static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) -
66                1) == k_num_gpr_registers_arm64,
67               "g_gpr_regnums_arm64 has wrong number of register infos");
68 
69 // ARM64 floating point registers.
70 static const uint32_t g_fpu_regnums_arm64[] = {
71     fpu_v0_arm64,       fpu_v1_arm64,   fpu_v2_arm64,  fpu_v3_arm64,
72     fpu_v4_arm64,       fpu_v5_arm64,   fpu_v6_arm64,  fpu_v7_arm64,
73     fpu_v8_arm64,       fpu_v9_arm64,   fpu_v10_arm64, fpu_v11_arm64,
74     fpu_v12_arm64,      fpu_v13_arm64,  fpu_v14_arm64, fpu_v15_arm64,
75     fpu_v16_arm64,      fpu_v17_arm64,  fpu_v18_arm64, fpu_v19_arm64,
76     fpu_v20_arm64,      fpu_v21_arm64,  fpu_v22_arm64, fpu_v23_arm64,
77     fpu_v24_arm64,      fpu_v25_arm64,  fpu_v26_arm64, fpu_v27_arm64,
78     fpu_v28_arm64,      fpu_v29_arm64,  fpu_v30_arm64, fpu_v31_arm64,
79     fpu_s0_arm64,       fpu_s1_arm64,   fpu_s2_arm64,  fpu_s3_arm64,
80     fpu_s4_arm64,       fpu_s5_arm64,   fpu_s6_arm64,  fpu_s7_arm64,
81     fpu_s8_arm64,       fpu_s9_arm64,   fpu_s10_arm64, fpu_s11_arm64,
82     fpu_s12_arm64,      fpu_s13_arm64,  fpu_s14_arm64, fpu_s15_arm64,
83     fpu_s16_arm64,      fpu_s17_arm64,  fpu_s18_arm64, fpu_s19_arm64,
84     fpu_s20_arm64,      fpu_s21_arm64,  fpu_s22_arm64, fpu_s23_arm64,
85     fpu_s24_arm64,      fpu_s25_arm64,  fpu_s26_arm64, fpu_s27_arm64,
86     fpu_s28_arm64,      fpu_s29_arm64,  fpu_s30_arm64, fpu_s31_arm64,
87 
88     fpu_d0_arm64,       fpu_d1_arm64,   fpu_d2_arm64,  fpu_d3_arm64,
89     fpu_d4_arm64,       fpu_d5_arm64,   fpu_d6_arm64,  fpu_d7_arm64,
90     fpu_d8_arm64,       fpu_d9_arm64,   fpu_d10_arm64, fpu_d11_arm64,
91     fpu_d12_arm64,      fpu_d13_arm64,  fpu_d14_arm64, fpu_d15_arm64,
92     fpu_d16_arm64,      fpu_d17_arm64,  fpu_d18_arm64, fpu_d19_arm64,
93     fpu_d20_arm64,      fpu_d21_arm64,  fpu_d22_arm64, fpu_d23_arm64,
94     fpu_d24_arm64,      fpu_d25_arm64,  fpu_d26_arm64, fpu_d27_arm64,
95     fpu_d28_arm64,      fpu_d29_arm64,  fpu_d30_arm64, fpu_d31_arm64,
96     fpu_fpsr_arm64,     fpu_fpcr_arm64,
97     LLDB_INVALID_REGNUM // register sets need to end with this flag
98 };
99 static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) -
100                1) == k_num_fpr_registers_arm64,
101               "g_fpu_regnums_arm64 has wrong number of register infos");
102 
103 namespace {
104 // Number of register sets provided by this context.
105 enum { k_num_register_sets = 2 };
106 }
107 
108 // Register sets for ARM64.
109 static const RegisterSet g_reg_sets_arm64[k_num_register_sets] = {
110     {"General Purpose Registers", "gpr", k_num_gpr_registers_arm64,
111      g_gpr_regnums_arm64},
112     {"Floating Point Registers", "fpu", k_num_fpr_registers_arm64,
113      g_fpu_regnums_arm64}};
114 
115 NativeRegisterContextLinux *
116 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
117     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
118     uint32_t concrete_frame_idx) {
119   switch (target_arch.GetMachine()) {
120   case llvm::Triple::arm:
121     return new NativeRegisterContextLinux_arm(target_arch, native_thread,
122                                               concrete_frame_idx);
123   case llvm::Triple::aarch64:
124     return new NativeRegisterContextLinux_arm64(target_arch, native_thread,
125                                                 concrete_frame_idx);
126   default:
127     llvm_unreachable("have no register context for architecture");
128   }
129 }
130 
131 NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
132     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
133     uint32_t concrete_frame_idx)
134     : NativeRegisterContextLinux(native_thread, concrete_frame_idx,
135                                  new RegisterInfoPOSIX_arm64(target_arch)) {
136   switch (target_arch.GetMachine()) {
137   case llvm::Triple::aarch64:
138     m_reg_info.num_registers = k_num_registers_arm64;
139     m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64;
140     m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64;
141     m_reg_info.last_gpr = k_last_gpr_arm64;
142     m_reg_info.first_fpr = k_first_fpr_arm64;
143     m_reg_info.last_fpr = k_last_fpr_arm64;
144     m_reg_info.first_fpr_v = fpu_v0_arm64;
145     m_reg_info.last_fpr_v = fpu_v31_arm64;
146     m_reg_info.gpr_flags = gpr_cpsr_arm64;
147     break;
148   default:
149     llvm_unreachable("Unhandled target architecture.");
150     break;
151   }
152 
153   ::memset(&m_fpr, 0, sizeof(m_fpr));
154   ::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64));
155   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
156 
157   // 16 is just a maximum value, query hardware for actual watchpoint count
158   m_max_hwp_supported = 16;
159   m_max_hbp_supported = 16;
160   m_refresh_hwdebug_info = true;
161 }
162 
163 uint32_t NativeRegisterContextLinux_arm64::GetRegisterSetCount() const {
164   return k_num_register_sets;
165 }
166 
167 const RegisterSet *
168 NativeRegisterContextLinux_arm64::GetRegisterSet(uint32_t set_index) const {
169   if (set_index < k_num_register_sets)
170     return &g_reg_sets_arm64[set_index];
171 
172   return nullptr;
173 }
174 
175 uint32_t NativeRegisterContextLinux_arm64::GetUserRegisterCount() const {
176   uint32_t count = 0;
177   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
178     count += g_reg_sets_arm64[set_index].num_registers;
179   return count;
180 }
181 
182 Error NativeRegisterContextLinux_arm64::ReadRegister(
183     const RegisterInfo *reg_info, RegisterValue &reg_value) {
184   Error error;
185 
186   if (!reg_info) {
187     error.SetErrorString("reg_info NULL");
188     return error;
189   }
190 
191   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
192 
193   if (IsFPR(reg)) {
194     error = ReadFPR();
195     if (error.Fail())
196       return error;
197   } else {
198     uint32_t full_reg = reg;
199     bool is_subreg = reg_info->invalidate_regs &&
200                      (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
201 
202     if (is_subreg) {
203       // Read the full aligned 64-bit register.
204       full_reg = reg_info->invalidate_regs[0];
205     }
206 
207     error = ReadRegisterRaw(full_reg, reg_value);
208 
209     if (error.Success()) {
210       // If our read was not aligned (for ah,bh,ch,dh), shift our returned value
211       // one byte to the right.
212       if (is_subreg && (reg_info->byte_offset & 0x1))
213         reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
214 
215       // If our return byte size was greater than the return value reg size,
216       // then
217       // use the type specified by reg_info rather than the uint64_t default
218       if (reg_value.GetByteSize() > reg_info->byte_size)
219         reg_value.SetType(reg_info);
220     }
221     return error;
222   }
223 
224   // Get pointer to m_fpr variable and set the data from it.
225   uint32_t fpr_offset = CalculateFprOffset(reg_info);
226   assert(fpr_offset < sizeof m_fpr);
227   uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
228   reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
229                               eByteOrderLittle, error);
230 
231   return error;
232 }
233 
234 Error NativeRegisterContextLinux_arm64::WriteRegister(
235     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
236   if (!reg_info)
237     return Error("reg_info NULL");
238 
239   const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
240   if (reg_index == LLDB_INVALID_REGNUM)
241     return Error("no lldb regnum for %s", reg_info && reg_info->name
242                                               ? reg_info->name
243                                               : "<unknown register>");
244 
245   if (IsGPR(reg_index))
246     return WriteRegisterRaw(reg_index, reg_value);
247 
248   if (IsFPR(reg_index)) {
249     // Get pointer to m_fpr variable and set the data to it.
250     uint32_t fpr_offset = CalculateFprOffset(reg_info);
251     assert(fpr_offset < sizeof m_fpr);
252     uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
253     switch (reg_info->byte_size) {
254     case 2:
255       *(uint16_t *)dst = reg_value.GetAsUInt16();
256       break;
257     case 4:
258       *(uint32_t *)dst = reg_value.GetAsUInt32();
259       break;
260     case 8:
261       *(uint64_t *)dst = reg_value.GetAsUInt64();
262       break;
263     default:
264       assert(false && "Unhandled data size.");
265       return Error("unhandled register data size %" PRIu32,
266                    reg_info->byte_size);
267     }
268 
269     Error error = WriteFPR();
270     if (error.Fail())
271       return error;
272 
273     return Error();
274   }
275 
276   return Error("failed - register wasn't recognized to be a GPR or an FPR, "
277                "write strategy unknown");
278 }
279 
280 Error NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
281     lldb::DataBufferSP &data_sp) {
282   Error error;
283 
284   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
285   if (!data_sp)
286     return Error("failed to allocate DataBufferHeap instance of size %" PRIu64,
287                  REG_CONTEXT_SIZE);
288 
289   error = ReadGPR();
290   if (error.Fail())
291     return error;
292 
293   error = ReadFPR();
294   if (error.Fail())
295     return error;
296 
297   uint8_t *dst = data_sp->GetBytes();
298   if (dst == nullptr) {
299     error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
300                                    " returned a null pointer",
301                                    REG_CONTEXT_SIZE);
302     return error;
303   }
304 
305   ::memcpy(dst, &m_gpr_arm64, GetGPRSize());
306   dst += GetGPRSize();
307   ::memcpy(dst, &m_fpr, sizeof(m_fpr));
308 
309   return error;
310 }
311 
312 Error NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
313     const lldb::DataBufferSP &data_sp) {
314   Error error;
315 
316   if (!data_sp) {
317     error.SetErrorStringWithFormat(
318         "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided",
319         __FUNCTION__);
320     return error;
321   }
322 
323   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
324     error.SetErrorStringWithFormat(
325         "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched "
326         "data size, expected %" PRIu64 ", actual %" PRIu64,
327         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
328     return error;
329   }
330 
331   uint8_t *src = data_sp->GetBytes();
332   if (src == nullptr) {
333     error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s "
334                                    "DataBuffer::GetBytes() returned a null "
335                                    "pointer",
336                                    __FUNCTION__);
337     return error;
338   }
339   ::memcpy(&m_gpr_arm64, src, GetRegisterInfoInterface().GetGPRSize());
340 
341   error = WriteGPR();
342   if (error.Fail())
343     return error;
344 
345   src += GetRegisterInfoInterface().GetGPRSize();
346   ::memcpy(&m_fpr, src, sizeof(m_fpr));
347 
348   error = WriteFPR();
349   if (error.Fail())
350     return error;
351 
352   return error;
353 }
354 
355 bool NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const {
356   return reg <= m_reg_info.last_gpr; // GPR's come first.
357 }
358 
359 bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const {
360   return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
361 }
362 
363 uint32_t
364 NativeRegisterContextLinux_arm64::SetHardwareBreakpoint(lldb::addr_t addr,
365                                                         size_t size) {
366   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
367   LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
368 
369   // Read hardware breakpoint and watchpoint information.
370   Error error = ReadHardwareDebugInfo();
371 
372   if (error.Fail())
373     return LLDB_INVALID_INDEX32;
374 
375   uint32_t control_value = 0, bp_index = 0;
376 
377   // Check if size has a valid hardware breakpoint length.
378   if (size != 4)
379     return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware
380                                  // breakpoint
381 
382   // Check 4-byte alignment for hardware breakpoint target address.
383   if (addr & 0x03)
384     return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
385 
386   // Setup control value
387   control_value = 0;
388   control_value |= ((1 << size) - 1) << 5;
389   control_value |= (2 << 1) | 1;
390 
391   // Iterate over stored hardware breakpoints
392   // Find a free bp_index or update reference count if duplicate.
393   bp_index = LLDB_INVALID_INDEX32;
394   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
395     if ((m_hbr_regs[i].control & 1) == 0) {
396       bp_index = i; // Mark last free slot
397     } else if (m_hbr_regs[i].address == addr &&
398                m_hbr_regs[i].control == control_value) {
399       bp_index = i; // Mark duplicate index
400       break;        // Stop searching here
401     }
402   }
403 
404   if (bp_index == LLDB_INVALID_INDEX32)
405     return LLDB_INVALID_INDEX32;
406 
407   // Add new or update existing breakpoint
408   if ((m_hbr_regs[bp_index].control & 1) == 0) {
409     m_hbr_regs[bp_index].address = addr;
410     m_hbr_regs[bp_index].control = control_value;
411     m_hbr_regs[bp_index].refcount = 1;
412 
413     // PTRACE call to set corresponding hardware breakpoint register.
414     error = WriteHardwareDebugRegs(eDREGTypeBREAK);
415 
416     if (error.Fail()) {
417       m_hbr_regs[bp_index].address = 0;
418       m_hbr_regs[bp_index].control &= ~1;
419       m_hbr_regs[bp_index].refcount = 0;
420 
421       return LLDB_INVALID_INDEX32;
422     }
423   } else
424     m_hbr_regs[bp_index].refcount++;
425 
426   return bp_index;
427 }
428 
429 bool NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint(
430     uint32_t hw_idx) {
431   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
432   LLDB_LOG(log, "hw_idx: {0}", hw_idx);
433 
434   // Read hardware breakpoint and watchpoint information.
435   Error error = ReadHardwareDebugInfo();
436 
437   if (error.Fail())
438     return false;
439 
440   if (hw_idx >= m_max_hbp_supported)
441     return false;
442 
443   // Update reference count if multiple references.
444   if (m_hbr_regs[hw_idx].refcount > 1) {
445     m_hbr_regs[hw_idx].refcount--;
446     return true;
447   } else if (m_hbr_regs[hw_idx].refcount == 1) {
448     // Create a backup we can revert to in case of failure.
449     lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
450     uint32_t tempControl = m_hbr_regs[hw_idx].control;
451     uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount;
452 
453     m_hbr_regs[hw_idx].control &= ~1;
454     m_hbr_regs[hw_idx].address = 0;
455     m_hbr_regs[hw_idx].refcount = 0;
456 
457     // PTRACE call to clear corresponding hardware breakpoint register.
458     WriteHardwareDebugRegs(eDREGTypeBREAK);
459 
460     if (error.Fail()) {
461       m_hbr_regs[hw_idx].control = tempControl;
462       m_hbr_regs[hw_idx].address = tempAddr;
463       m_hbr_regs[hw_idx].refcount = tempRefCount;
464 
465       return false;
466     }
467 
468     return true;
469   }
470 
471   return false;
472 }
473 
474 uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints() {
475   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
476 
477   // Read hardware breakpoint and watchpoint information.
478   Error error = ReadHardwareDebugInfo();
479 
480   if (error.Fail())
481     return 0;
482 
483   LLDB_LOG(log, "{0}", m_max_hwp_supported);
484   return m_max_hwp_supported;
485 }
486 
487 uint32_t NativeRegisterContextLinux_arm64::SetHardwareWatchpoint(
488     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
489   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
490   LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
491            watch_flags);
492 
493   // Read hardware breakpoint and watchpoint information.
494   Error error = ReadHardwareDebugInfo();
495 
496   if (error.Fail())
497     return LLDB_INVALID_INDEX32;
498 
499   uint32_t control_value = 0, wp_index = 0;
500   lldb::addr_t real_addr = addr;
501 
502   // Check if we are setting watchpoint other than read/write/access
503   // Also update watchpoint flag to match AArch64 write-read bit configuration.
504   switch (watch_flags) {
505   case 1:
506     watch_flags = 2;
507     break;
508   case 2:
509     watch_flags = 1;
510     break;
511   case 3:
512     break;
513   default:
514     return LLDB_INVALID_INDEX32;
515   }
516 
517   // Check if size has a valid hardware watchpoint length.
518   if (size != 1 && size != 2 && size != 4 && size != 8)
519     return LLDB_INVALID_INDEX32;
520 
521   // Check 8-byte alignment for hardware watchpoint target address.
522   // Below is a hack to recalculate address and size in order to
523   // make sure we can watch non 8-byte alligned addresses as well.
524   if (addr & 0x07) {
525     uint8_t watch_mask = (addr & 0x07) + size;
526 
527     if (watch_mask > 0x08)
528       return LLDB_INVALID_INDEX32;
529     else if (watch_mask <= 0x02)
530       size = 2;
531     else if (watch_mask <= 0x04)
532       size = 4;
533     else
534       size = 8;
535 
536     addr = addr & (~0x07);
537   }
538 
539   // Setup control value
540   control_value = watch_flags << 3;
541   control_value |= ((1 << size) - 1) << 5;
542   control_value |= (2 << 1) | 1;
543 
544   // Iterate over stored watchpoints and find a free wp_index
545   wp_index = LLDB_INVALID_INDEX32;
546   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
547     if ((m_hwp_regs[i].control & 1) == 0) {
548       wp_index = i; // Mark last free slot
549     } else if (m_hwp_regs[i].address == addr) {
550       return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
551     }
552   }
553 
554   if (wp_index == LLDB_INVALID_INDEX32)
555     return LLDB_INVALID_INDEX32;
556 
557   // Update watchpoint in local cache
558   m_hwp_regs[wp_index].real_addr = real_addr;
559   m_hwp_regs[wp_index].address = addr;
560   m_hwp_regs[wp_index].control = control_value;
561 
562   // PTRACE call to set corresponding watchpoint register.
563   error = WriteHardwareDebugRegs(eDREGTypeWATCH);
564 
565   if (error.Fail()) {
566     m_hwp_regs[wp_index].address = 0;
567     m_hwp_regs[wp_index].control &= ~1;
568 
569     return LLDB_INVALID_INDEX32;
570   }
571 
572   return wp_index;
573 }
574 
575 bool NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint(
576     uint32_t wp_index) {
577   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
578   LLDB_LOG(log, "wp_index: {0}", wp_index);
579 
580   // Read hardware breakpoint and watchpoint information.
581   Error error = ReadHardwareDebugInfo();
582 
583   if (error.Fail())
584     return false;
585 
586   if (wp_index >= m_max_hwp_supported)
587     return false;
588 
589   // Create a backup we can revert to in case of failure.
590   lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
591   uint32_t tempControl = m_hwp_regs[wp_index].control;
592 
593   // Update watchpoint in local cache
594   m_hwp_regs[wp_index].control &= ~1;
595   m_hwp_regs[wp_index].address = 0;
596 
597   // Ptrace call to update hardware debug registers
598   error = WriteHardwareDebugRegs(eDREGTypeWATCH);
599 
600   if (error.Fail()) {
601     m_hwp_regs[wp_index].control = tempControl;
602     m_hwp_regs[wp_index].address = tempAddr;
603 
604     return false;
605   }
606 
607   return true;
608 }
609 
610 Error NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints() {
611   // Read hardware breakpoint and watchpoint information.
612   Error error = ReadHardwareDebugInfo();
613 
614   if (error.Fail())
615     return error;
616 
617   lldb::addr_t tempAddr = 0;
618   uint32_t tempControl = 0, tempRefCount = 0;
619 
620   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
621     if (m_hwp_regs[i].control & 0x01) {
622       // Create a backup we can revert to in case of failure.
623       tempAddr = m_hwp_regs[i].address;
624       tempControl = m_hwp_regs[i].control;
625 
626       // Clear watchpoints in local cache
627       m_hwp_regs[i].control &= ~1;
628       m_hwp_regs[i].address = 0;
629 
630       // Ptrace call to update hardware debug registers
631       error = WriteHardwareDebugRegs(eDREGTypeWATCH);
632 
633       if (error.Fail()) {
634         m_hwp_regs[i].control = tempControl;
635         m_hwp_regs[i].address = tempAddr;
636 
637         return error;
638       }
639     }
640   }
641 
642   return Error();
643 }
644 
645 uint32_t
646 NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) {
647   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
648   LLDB_LOG(log, "wp_index: {0}", wp_index);
649 
650   switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) {
651   case 0x01:
652     return 1;
653   case 0x03:
654     return 2;
655   case 0x0f:
656     return 4;
657   case 0xff:
658     return 8;
659   default:
660     return 0;
661   }
662 }
663 bool NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) {
664   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
665   LLDB_LOG(log, "wp_index: {0}", wp_index);
666 
667   if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
668     return true;
669   else
670     return false;
671 }
672 
673 Error NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(
674     uint32_t &wp_index, lldb::addr_t trap_addr) {
675   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
676   LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
677 
678   uint32_t watch_size;
679   lldb::addr_t watch_addr;
680 
681   for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
682     watch_size = GetWatchpointSize(wp_index);
683     watch_addr = m_hwp_regs[wp_index].address;
684 
685     if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
686         trap_addr < watch_addr + watch_size) {
687       m_hwp_regs[wp_index].hit_addr = trap_addr;
688       return Error();
689     }
690   }
691 
692   wp_index = LLDB_INVALID_INDEX32;
693   return Error();
694 }
695 
696 lldb::addr_t
697 NativeRegisterContextLinux_arm64::GetWatchpointAddress(uint32_t wp_index) {
698   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
699   LLDB_LOG(log, "wp_index: {0}", wp_index);
700 
701   if (wp_index >= m_max_hwp_supported)
702     return LLDB_INVALID_ADDRESS;
703 
704   if (WatchpointIsEnabled(wp_index))
705     return m_hwp_regs[wp_index].real_addr;
706   else
707     return LLDB_INVALID_ADDRESS;
708 }
709 
710 lldb::addr_t
711 NativeRegisterContextLinux_arm64::GetWatchpointHitAddress(uint32_t wp_index) {
712   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
713   LLDB_LOG(log, "wp_index: {0}", wp_index);
714 
715   if (wp_index >= m_max_hwp_supported)
716     return LLDB_INVALID_ADDRESS;
717 
718   if (WatchpointIsEnabled(wp_index))
719     return m_hwp_regs[wp_index].hit_addr;
720   else
721     return LLDB_INVALID_ADDRESS;
722 }
723 
724 Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
725   if (!m_refresh_hwdebug_info) {
726     return Error();
727   }
728 
729   ::pid_t tid = m_thread.GetID();
730 
731   int regset = NT_ARM_HW_WATCH;
732   struct iovec ioVec;
733   struct user_hwdebug_state dreg_state;
734   Error error;
735 
736   ioVec.iov_base = &dreg_state;
737   ioVec.iov_len = sizeof(dreg_state);
738   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
739                                             &ioVec, ioVec.iov_len);
740 
741   if (error.Fail())
742     return error;
743 
744   m_max_hwp_supported = dreg_state.dbg_info & 0xff;
745 
746   regset = NT_ARM_HW_BREAK;
747   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
748                                             &ioVec, ioVec.iov_len);
749 
750   if (error.Fail())
751     return error;
752 
753   m_max_hbp_supported = dreg_state.dbg_info & 0xff;
754   m_refresh_hwdebug_info = false;
755 
756   return error;
757 }
758 
759 Error NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) {
760   struct iovec ioVec;
761   struct user_hwdebug_state dreg_state;
762   Error error;
763 
764   memset(&dreg_state, 0, sizeof(dreg_state));
765   ioVec.iov_base = &dreg_state;
766 
767   if (hwbType == eDREGTypeWATCH) {
768     hwbType = NT_ARM_HW_WATCH;
769     ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
770                     (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
771 
772     for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
773       dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
774       dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
775     }
776   } else {
777     hwbType = NT_ARM_HW_BREAK;
778     ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
779                     (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
780 
781     for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
782       dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address;
783       dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control;
784     }
785   }
786 
787   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
788                                            &hwbType, &ioVec, ioVec.iov_len);
789 }
790 
791 Error NativeRegisterContextLinux_arm64::DoReadRegisterValue(
792     uint32_t offset, const char *reg_name, uint32_t size,
793     RegisterValue &value) {
794   Error error;
795   if (offset > sizeof(struct user_pt_regs)) {
796     uintptr_t offset = offset - sizeof(struct user_pt_regs);
797     if (offset > sizeof(struct user_fpsimd_state)) {
798       error.SetErrorString("invalid offset value");
799       return error;
800     }
801     elf_fpregset_t regs;
802     int regset = NT_FPREGSET;
803     struct iovec ioVec;
804 
805     ioVec.iov_base = &regs;
806     ioVec.iov_len = sizeof regs;
807     error = NativeProcessLinux::PtraceWrapper(
808         PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
809     if (error.Success()) {
810       ArchSpec arch;
811       if (m_thread.GetProcess()->GetArchitecture(arch))
812         value.SetBytes((void *)(((unsigned char *)(&regs)) + offset), 16,
813                        arch.GetByteOrder());
814       else
815         error.SetErrorString("failed to get architecture");
816     }
817   } else {
818     elf_gregset_t regs;
819     int regset = NT_PRSTATUS;
820     struct iovec ioVec;
821 
822     ioVec.iov_base = &regs;
823     ioVec.iov_len = sizeof regs;
824     error = NativeProcessLinux::PtraceWrapper(
825         PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
826     if (error.Success()) {
827       ArchSpec arch;
828       if (m_thread.GetProcess()->GetArchitecture(arch))
829         value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8,
830                        arch.GetByteOrder());
831       else
832         error.SetErrorString("failed to get architecture");
833     }
834   }
835   return error;
836 }
837 
838 Error NativeRegisterContextLinux_arm64::DoWriteRegisterValue(
839     uint32_t offset, const char *reg_name, const RegisterValue &value) {
840   Error error;
841   ::pid_t tid = m_thread.GetID();
842   if (offset > sizeof(struct user_pt_regs)) {
843     uintptr_t offset = offset - sizeof(struct user_pt_regs);
844     if (offset > sizeof(struct user_fpsimd_state)) {
845       error.SetErrorString("invalid offset value");
846       return error;
847     }
848     elf_fpregset_t regs;
849     int regset = NT_FPREGSET;
850     struct iovec ioVec;
851 
852     ioVec.iov_base = &regs;
853     ioVec.iov_len = sizeof regs;
854     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
855                                               &ioVec, sizeof regs);
856 
857     if (error.Success()) {
858       ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(),
859                16);
860       error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset,
861                                                 &ioVec, sizeof regs);
862     }
863   } else {
864     elf_gregset_t regs;
865     int regset = NT_PRSTATUS;
866     struct iovec ioVec;
867 
868     ioVec.iov_base = &regs;
869     ioVec.iov_len = sizeof regs;
870     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
871                                               &ioVec, sizeof regs);
872     if (error.Success()) {
873       ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(),
874                8);
875       error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset,
876                                                 &ioVec, sizeof regs);
877     }
878   }
879   return error;
880 }
881 
882 Error NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) {
883   int regset = NT_PRSTATUS;
884   struct iovec ioVec;
885   Error error;
886 
887   ioVec.iov_base = buf;
888   ioVec.iov_len = buf_size;
889   return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
890                                            &regset, &ioVec, buf_size);
891 }
892 
893 Error NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) {
894   int regset = NT_PRSTATUS;
895   struct iovec ioVec;
896   Error error;
897 
898   ioVec.iov_base = buf;
899   ioVec.iov_len = buf_size;
900   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
901                                            &regset, &ioVec, buf_size);
902 }
903 
904 Error NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) {
905   int regset = NT_FPREGSET;
906   struct iovec ioVec;
907   Error error;
908 
909   ioVec.iov_base = buf;
910   ioVec.iov_len = buf_size;
911   return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
912                                            &regset, &ioVec, buf_size);
913 }
914 
915 Error NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) {
916   int regset = NT_FPREGSET;
917   struct iovec ioVec;
918   Error error;
919 
920   ioVec.iov_base = buf;
921   ioVec.iov_len = buf_size;
922   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
923                                            &regset, &ioVec, buf_size);
924 }
925 
926 uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset(
927     const RegisterInfo *reg_info) const {
928   return reg_info->byte_offset -
929          GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
930 }
931 
932 #endif // defined (__arm64__) || defined (__aarch64__)
933