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