1 //===-- NativeRegisterContextLinux_arm64.cpp ------------------------------===//
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 
25 // System includes - They have to be included after framework includes because
26 // they define some macros which collide with variable names in other modules
27 #include <sys/socket.h>
28 // NT_PRSTATUS and NT_FPREGSET definition
29 #include <elf.h>
30 // user_hwdebug_state definition
31 #include <asm/ptrace.h>
32 
33 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
34 
35 using namespace lldb;
36 using namespace lldb_private;
37 using namespace lldb_private::process_linux;
38 
39 std::unique_ptr<NativeRegisterContextLinux>
40 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
41     const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
42   switch (target_arch.GetMachine()) {
43   case llvm::Triple::arm:
44     return std::make_unique<NativeRegisterContextLinux_arm>(target_arch,
45                                                              native_thread);
46   case llvm::Triple::aarch64:
47     return std::make_unique<NativeRegisterContextLinux_arm64>(target_arch,
48                                                                native_thread);
49   default:
50     llvm_unreachable("have no register context for architecture");
51   }
52 }
53 
54 NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
55     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
56     : NativeRegisterContextLinux(native_thread,
57                                  new RegisterInfoPOSIX_arm64(target_arch)) {
58   ::memset(&m_fpr, 0, sizeof(m_fpr));
59   ::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64));
60   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
61   ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs));
62 
63   // 16 is just a maximum value, query hardware for actual watchpoint count
64   m_max_hwp_supported = 16;
65   m_max_hbp_supported = 16;
66   m_refresh_hwdebug_info = true;
67 
68   m_gpr_is_valid = false;
69   m_fpu_is_valid = false;
70 }
71 
72 RegisterInfoPOSIX_arm64 &
73 NativeRegisterContextLinux_arm64::GetRegisterInfo() const {
74   return static_cast<RegisterInfoPOSIX_arm64 &>(*m_register_info_interface_up);
75 }
76 
77 uint32_t NativeRegisterContextLinux_arm64::GetRegisterSetCount() const {
78   return GetRegisterInfo().GetRegisterSetCount();
79 }
80 
81 const RegisterSet *
82 NativeRegisterContextLinux_arm64::GetRegisterSet(uint32_t set_index) const {
83   return GetRegisterInfo().GetRegisterSet(set_index);
84 }
85 
86 uint32_t NativeRegisterContextLinux_arm64::GetUserRegisterCount() const {
87   uint32_t count = 0;
88   for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
89     count += GetRegisterSet(set_index)->num_registers;
90   return count;
91 }
92 
93 Status
94 NativeRegisterContextLinux_arm64::ReadRegister(const RegisterInfo *reg_info,
95                                                RegisterValue &reg_value) {
96   Status error;
97 
98   if (!reg_info) {
99     error.SetErrorString("reg_info NULL");
100     return error;
101   }
102 
103   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
104 
105   if (reg == LLDB_INVALID_REGNUM)
106     return Status("no lldb regnum for %s", reg_info && reg_info->name
107                                                ? reg_info->name
108                                                : "<unknown register>");
109 
110   uint8_t *src;
111   uint32_t offset;
112 
113   if (IsGPR(reg)) {
114     if (!m_gpr_is_valid) {
115       error = ReadGPR();
116       if (error.Fail())
117         return error;
118     }
119 
120     offset = reg_info->byte_offset;
121     assert(offset < GetGPRSize());
122     src = (uint8_t *)GetGPRBuffer() + offset;
123 
124   } else if (IsFPR(reg)) {
125     if (!m_fpu_is_valid) {
126 
127       error = ReadFPR();
128       if (error.Fail())
129         return error;
130     }
131     offset = CalculateFprOffset(reg_info);
132     assert(offset < GetFPRSize());
133     src = (uint8_t *)GetFPRBuffer() + offset;
134   } else
135     return Status("failed - register wasn't recognized to be a GPR or an FPR, "
136                   "write strategy unknown");
137 
138   reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
139                               eByteOrderLittle, error);
140 
141   return error;
142 }
143 
144 Status NativeRegisterContextLinux_arm64::WriteRegister(
145     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
146   Status error;
147 
148   if (!reg_info)
149     return Status("reg_info NULL");
150 
151   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
152 
153   if (reg == LLDB_INVALID_REGNUM)
154     return Status("no lldb regnum for %s", reg_info && reg_info->name
155                                                ? reg_info->name
156                                                : "<unknown register>");
157 
158   uint8_t *dst;
159   uint32_t offset;
160 
161   if (IsGPR(reg)) {
162     if (!m_gpr_is_valid) {
163       error = ReadGPR();
164       if (error.Fail())
165         return error;
166     }
167 
168     offset = reg_info->byte_offset;
169     assert(offset < GetGPRSize());
170     dst = (uint8_t *)GetGPRBuffer() + offset;
171 
172     ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
173 
174     return WriteGPR();
175   } else if (IsFPR(reg)) {
176     if (!m_fpu_is_valid) {
177       error = ReadFPR();
178       if (error.Fail())
179         return error;
180     }
181     offset = CalculateFprOffset(reg_info);
182     assert(offset < GetFPRSize());
183     dst = (uint8_t *)GetFPRBuffer() + offset;
184 
185     ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
186 
187     return WriteFPR();
188   }
189 
190   return error;
191 }
192 
193 Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
194     lldb::DataBufferSP &data_sp) {
195   Status error;
196 
197   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
198   if (!m_gpr_is_valid) {
199     error = ReadGPR();
200     if (error.Fail())
201       return error;
202   }
203 
204   if (!m_fpu_is_valid) {
205     error = ReadFPR();
206     if (error.Fail())
207       return error;
208   }
209   uint8_t *dst = data_sp->GetBytes();
210   ::memcpy(dst, GetGPRBuffer(), GetGPRSize());
211   dst += GetGPRSize();
212   ::memcpy(dst, GetFPRBuffer(), GetFPRSize());
213 
214   return error;
215 }
216 
217 Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
218     const lldb::DataBufferSP &data_sp) {
219   Status error;
220 
221   if (!data_sp) {
222     error.SetErrorStringWithFormat(
223         "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided",
224         __FUNCTION__);
225     return error;
226   }
227 
228   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
229     error.SetErrorStringWithFormat(
230         "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched "
231         "data size, expected %" PRIu64 ", actual %" PRIu64,
232         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
233     return error;
234   }
235 
236   uint8_t *src = data_sp->GetBytes();
237   if (src == nullptr) {
238     error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s "
239                                    "DataBuffer::GetBytes() returned a null "
240                                    "pointer",
241                                    __FUNCTION__);
242     return error;
243   }
244   ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize());
245 
246   error = WriteGPR();
247   if (error.Fail())
248     return error;
249 
250   src += GetRegisterInfoInterface().GetGPRSize();
251   ::memcpy(GetFPRBuffer(), src, GetFPRSize());
252 
253   error = WriteFPR();
254   if (error.Fail())
255     return error;
256 
257   return error;
258 }
259 
260 bool NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const {
261   if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
262       RegisterInfoPOSIX_arm64::GPRegSet)
263     return true;
264   return false;
265 }
266 
267 bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const {
268   if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
269       RegisterInfoPOSIX_arm64::FPRegSet)
270     return true;
271   return false;
272 }
273 
274 uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareBreakpoints() {
275   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
276 
277   LLDB_LOGF(log, "NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
278 
279   Status error;
280 
281   // Read hardware breakpoint and watchpoint information.
282   error = ReadHardwareDebugInfo();
283 
284   if (error.Fail())
285     return 0;
286 
287   return m_max_hbp_supported;
288 }
289 
290 uint32_t
291 NativeRegisterContextLinux_arm64::SetHardwareBreakpoint(lldb::addr_t addr,
292                                                         size_t size) {
293   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
294   LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
295 
296   // Read hardware breakpoint and watchpoint information.
297   Status error = ReadHardwareDebugInfo();
298 
299   if (error.Fail())
300     return LLDB_INVALID_INDEX32;
301 
302   uint32_t control_value = 0, bp_index = 0;
303 
304   // Check if size has a valid hardware breakpoint length.
305   if (size != 4)
306     return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware
307                                  // breakpoint
308 
309   // Check 4-byte alignment for hardware breakpoint target address.
310   if (addr & 0x03)
311     return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
312 
313   // Setup control value
314   control_value = 0;
315   control_value |= ((1 << size) - 1) << 5;
316   control_value |= (2 << 1) | 1;
317 
318   // Iterate over stored breakpoints and find a free bp_index
319   bp_index = LLDB_INVALID_INDEX32;
320   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
321     if ((m_hbr_regs[i].control & 1) == 0) {
322       bp_index = i; // Mark last free slot
323     } else if (m_hbr_regs[i].address == addr) {
324       return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
325     }
326   }
327 
328   if (bp_index == LLDB_INVALID_INDEX32)
329     return LLDB_INVALID_INDEX32;
330 
331   // Update breakpoint in local cache
332   m_hbr_regs[bp_index].real_addr = addr;
333   m_hbr_regs[bp_index].address = addr;
334   m_hbr_regs[bp_index].control = control_value;
335 
336   // PTRACE call to set corresponding hardware breakpoint register.
337   error = WriteHardwareDebugRegs(eDREGTypeBREAK);
338 
339   if (error.Fail()) {
340     m_hbr_regs[bp_index].address = 0;
341     m_hbr_regs[bp_index].control &= ~1;
342 
343     return LLDB_INVALID_INDEX32;
344   }
345 
346   return bp_index;
347 }
348 
349 bool NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint(
350     uint32_t hw_idx) {
351   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
352   LLDB_LOG(log, "hw_idx: {0}", hw_idx);
353 
354   // Read hardware breakpoint and watchpoint information.
355   Status error = ReadHardwareDebugInfo();
356 
357   if (error.Fail())
358     return false;
359 
360   if (hw_idx >= m_max_hbp_supported)
361     return false;
362 
363   // Create a backup we can revert to in case of failure.
364   lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
365   uint32_t tempControl = m_hbr_regs[hw_idx].control;
366 
367   m_hbr_regs[hw_idx].control &= ~1;
368   m_hbr_regs[hw_idx].address = 0;
369 
370   // PTRACE call to clear corresponding hardware breakpoint register.
371   error = WriteHardwareDebugRegs(eDREGTypeBREAK);
372 
373   if (error.Fail()) {
374     m_hbr_regs[hw_idx].control = tempControl;
375     m_hbr_regs[hw_idx].address = tempAddr;
376 
377     return false;
378   }
379 
380   return true;
381 }
382 
383 Status NativeRegisterContextLinux_arm64::GetHardwareBreakHitIndex(
384     uint32_t &bp_index, lldb::addr_t trap_addr) {
385   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
386 
387   LLDB_LOGF(log, "NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
388 
389   lldb::addr_t break_addr;
390 
391   for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
392     break_addr = m_hbr_regs[bp_index].address;
393 
394     if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
395       m_hbr_regs[bp_index].hit_addr = trap_addr;
396       return Status();
397     }
398   }
399 
400   bp_index = LLDB_INVALID_INDEX32;
401   return Status();
402 }
403 
404 Status NativeRegisterContextLinux_arm64::ClearAllHardwareBreakpoints() {
405   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
406 
407   LLDB_LOGF(log, "NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
408 
409   Status error;
410 
411   // Read hardware breakpoint and watchpoint information.
412   error = ReadHardwareDebugInfo();
413 
414   if (error.Fail())
415     return error;
416 
417   lldb::addr_t tempAddr = 0;
418   uint32_t tempControl = 0;
419 
420   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
421     if (m_hbr_regs[i].control & 0x01) {
422       // Create a backup we can revert to in case of failure.
423       tempAddr = m_hbr_regs[i].address;
424       tempControl = m_hbr_regs[i].control;
425 
426       // Clear watchpoints in local cache
427       m_hbr_regs[i].control &= ~1;
428       m_hbr_regs[i].address = 0;
429 
430       // Ptrace call to update hardware debug registers
431       error = WriteHardwareDebugRegs(eDREGTypeBREAK);
432 
433       if (error.Fail()) {
434         m_hbr_regs[i].control = tempControl;
435         m_hbr_regs[i].address = tempAddr;
436 
437         return error;
438       }
439     }
440   }
441 
442   return Status();
443 }
444 
445 uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints() {
446   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
447 
448   // Read hardware breakpoint and watchpoint information.
449   Status error = ReadHardwareDebugInfo();
450 
451   if (error.Fail())
452     return 0;
453 
454   LLDB_LOG(log, "{0}", m_max_hwp_supported);
455   return m_max_hwp_supported;
456 }
457 
458 uint32_t NativeRegisterContextLinux_arm64::SetHardwareWatchpoint(
459     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
460   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
461   LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
462            watch_flags);
463 
464   // Read hardware breakpoint and watchpoint information.
465   Status error = ReadHardwareDebugInfo();
466 
467   if (error.Fail())
468     return LLDB_INVALID_INDEX32;
469 
470   uint32_t control_value = 0, wp_index = 0;
471   lldb::addr_t real_addr = addr;
472 
473   // Check if we are setting watchpoint other than read/write/access Also
474   // update watchpoint flag to match AArch64 write-read bit configuration.
475   switch (watch_flags) {
476   case 1:
477     watch_flags = 2;
478     break;
479   case 2:
480     watch_flags = 1;
481     break;
482   case 3:
483     break;
484   default:
485     return LLDB_INVALID_INDEX32;
486   }
487 
488   // Check if size has a valid hardware watchpoint length.
489   if (size != 1 && size != 2 && size != 4 && size != 8)
490     return LLDB_INVALID_INDEX32;
491 
492   // Check 8-byte alignment for hardware watchpoint target address. Below is a
493   // hack to recalculate address and size in order to make sure we can watch
494   // non 8-byte aligned addresses as well.
495   if (addr & 0x07) {
496     uint8_t watch_mask = (addr & 0x07) + size;
497 
498     if (watch_mask > 0x08)
499       return LLDB_INVALID_INDEX32;
500     else if (watch_mask <= 0x02)
501       size = 2;
502     else if (watch_mask <= 0x04)
503       size = 4;
504     else
505       size = 8;
506 
507     addr = addr & (~0x07);
508   }
509 
510   // Setup control value
511   control_value = watch_flags << 3;
512   control_value |= ((1 << size) - 1) << 5;
513   control_value |= (2 << 1) | 1;
514 
515   // Iterate over stored watchpoints and find a free wp_index
516   wp_index = LLDB_INVALID_INDEX32;
517   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
518     if ((m_hwp_regs[i].control & 1) == 0) {
519       wp_index = i; // Mark last free slot
520     } else if (m_hwp_regs[i].address == addr) {
521       return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
522     }
523   }
524 
525   if (wp_index == LLDB_INVALID_INDEX32)
526     return LLDB_INVALID_INDEX32;
527 
528   // Update watchpoint in local cache
529   m_hwp_regs[wp_index].real_addr = real_addr;
530   m_hwp_regs[wp_index].address = addr;
531   m_hwp_regs[wp_index].control = control_value;
532 
533   // PTRACE call to set corresponding watchpoint register.
534   error = WriteHardwareDebugRegs(eDREGTypeWATCH);
535 
536   if (error.Fail()) {
537     m_hwp_regs[wp_index].address = 0;
538     m_hwp_regs[wp_index].control &= ~1;
539 
540     return LLDB_INVALID_INDEX32;
541   }
542 
543   return wp_index;
544 }
545 
546 bool NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint(
547     uint32_t wp_index) {
548   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
549   LLDB_LOG(log, "wp_index: {0}", wp_index);
550 
551   // Read hardware breakpoint and watchpoint information.
552   Status error = ReadHardwareDebugInfo();
553 
554   if (error.Fail())
555     return false;
556 
557   if (wp_index >= m_max_hwp_supported)
558     return false;
559 
560   // Create a backup we can revert to in case of failure.
561   lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
562   uint32_t tempControl = m_hwp_regs[wp_index].control;
563 
564   // Update watchpoint in local cache
565   m_hwp_regs[wp_index].control &= ~1;
566   m_hwp_regs[wp_index].address = 0;
567 
568   // Ptrace call to update hardware debug registers
569   error = WriteHardwareDebugRegs(eDREGTypeWATCH);
570 
571   if (error.Fail()) {
572     m_hwp_regs[wp_index].control = tempControl;
573     m_hwp_regs[wp_index].address = tempAddr;
574 
575     return false;
576   }
577 
578   return true;
579 }
580 
581 Status NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints() {
582   // Read hardware breakpoint and watchpoint information.
583   Status error = ReadHardwareDebugInfo();
584 
585   if (error.Fail())
586     return error;
587 
588   lldb::addr_t tempAddr = 0;
589   uint32_t tempControl = 0;
590 
591   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
592     if (m_hwp_regs[i].control & 0x01) {
593       // Create a backup we can revert to in case of failure.
594       tempAddr = m_hwp_regs[i].address;
595       tempControl = m_hwp_regs[i].control;
596 
597       // Clear watchpoints in local cache
598       m_hwp_regs[i].control &= ~1;
599       m_hwp_regs[i].address = 0;
600 
601       // Ptrace call to update hardware debug registers
602       error = WriteHardwareDebugRegs(eDREGTypeWATCH);
603 
604       if (error.Fail()) {
605         m_hwp_regs[i].control = tempControl;
606         m_hwp_regs[i].address = tempAddr;
607 
608         return error;
609       }
610     }
611   }
612 
613   return Status();
614 }
615 
616 uint32_t
617 NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) {
618   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
619   LLDB_LOG(log, "wp_index: {0}", wp_index);
620 
621   switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) {
622   case 0x01:
623     return 1;
624   case 0x03:
625     return 2;
626   case 0x0f:
627     return 4;
628   case 0xff:
629     return 8;
630   default:
631     return 0;
632   }
633 }
634 bool NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) {
635   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
636   LLDB_LOG(log, "wp_index: {0}", wp_index);
637 
638   if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
639     return true;
640   else
641     return false;
642 }
643 
644 Status NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(
645     uint32_t &wp_index, lldb::addr_t trap_addr) {
646   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
647   LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
648 
649   uint32_t watch_size;
650   lldb::addr_t watch_addr;
651 
652   for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
653     watch_size = GetWatchpointSize(wp_index);
654     watch_addr = m_hwp_regs[wp_index].address;
655 
656     if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
657         trap_addr < watch_addr + watch_size) {
658       m_hwp_regs[wp_index].hit_addr = trap_addr;
659       return Status();
660     }
661   }
662 
663   wp_index = LLDB_INVALID_INDEX32;
664   return Status();
665 }
666 
667 lldb::addr_t
668 NativeRegisterContextLinux_arm64::GetWatchpointAddress(uint32_t wp_index) {
669   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
670   LLDB_LOG(log, "wp_index: {0}", wp_index);
671 
672   if (wp_index >= m_max_hwp_supported)
673     return LLDB_INVALID_ADDRESS;
674 
675   if (WatchpointIsEnabled(wp_index))
676     return m_hwp_regs[wp_index].real_addr;
677   else
678     return LLDB_INVALID_ADDRESS;
679 }
680 
681 lldb::addr_t
682 NativeRegisterContextLinux_arm64::GetWatchpointHitAddress(uint32_t wp_index) {
683   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
684   LLDB_LOG(log, "wp_index: {0}", wp_index);
685 
686   if (wp_index >= m_max_hwp_supported)
687     return LLDB_INVALID_ADDRESS;
688 
689   if (WatchpointIsEnabled(wp_index))
690     return m_hwp_regs[wp_index].hit_addr;
691   else
692     return LLDB_INVALID_ADDRESS;
693 }
694 
695 Status NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
696   if (!m_refresh_hwdebug_info) {
697     return Status();
698   }
699 
700   ::pid_t tid = m_thread.GetID();
701 
702   int regset = NT_ARM_HW_WATCH;
703   struct iovec ioVec;
704   struct user_hwdebug_state dreg_state;
705   Status error;
706 
707   ioVec.iov_base = &dreg_state;
708   ioVec.iov_len = sizeof(dreg_state);
709   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
710                                             &ioVec, ioVec.iov_len);
711 
712   if (error.Fail())
713     return error;
714 
715   m_max_hwp_supported = dreg_state.dbg_info & 0xff;
716 
717   regset = NT_ARM_HW_BREAK;
718   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
719                                             &ioVec, ioVec.iov_len);
720 
721   if (error.Fail())
722     return error;
723 
724   m_max_hbp_supported = dreg_state.dbg_info & 0xff;
725   m_refresh_hwdebug_info = false;
726 
727   return error;
728 }
729 
730 Status NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) {
731   struct iovec ioVec;
732   struct user_hwdebug_state dreg_state;
733   Status error;
734 
735   memset(&dreg_state, 0, sizeof(dreg_state));
736   ioVec.iov_base = &dreg_state;
737 
738   if (hwbType == eDREGTypeWATCH) {
739     hwbType = NT_ARM_HW_WATCH;
740     ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
741                     (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
742 
743     for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
744       dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
745       dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
746     }
747   } else {
748     hwbType = NT_ARM_HW_BREAK;
749     ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
750                     (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
751 
752     for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
753       dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address;
754       dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control;
755     }
756   }
757 
758   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
759                                            &hwbType, &ioVec, ioVec.iov_len);
760 }
761 
762 Status NativeRegisterContextLinux_arm64::ReadGPR() {
763   Status error;
764 
765   struct iovec ioVec;
766 
767   ioVec.iov_base = GetGPRBuffer();
768   ioVec.iov_len = GetGPRSize();
769 
770   error = ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
771 
772   if (error.Success())
773     m_gpr_is_valid = true;
774 
775   return error;
776 }
777 
778 Status NativeRegisterContextLinux_arm64::WriteGPR() {
779   struct iovec ioVec;
780 
781   m_gpr_is_valid = false;
782 
783   ioVec.iov_base = GetGPRBuffer();
784   ioVec.iov_len = GetGPRSize();
785 
786   return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
787 }
788 
789 Status NativeRegisterContextLinux_arm64::ReadFPR() {
790   Status error;
791 
792   struct iovec ioVec;
793 
794   ioVec.iov_base = GetFPRBuffer();
795   ioVec.iov_len = GetFPRSize();
796 
797   error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
798 
799   if (error.Success())
800     m_fpu_is_valid = true;
801 
802   return error;
803 }
804 
805 Status NativeRegisterContextLinux_arm64::WriteFPR() {
806   struct iovec ioVec;
807 
808   m_fpu_is_valid = false;
809 
810   ioVec.iov_base = GetFPRBuffer();
811   ioVec.iov_len = GetFPRSize();
812 
813   return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
814 }
815 
816 void NativeRegisterContextLinux_arm64::InvalidateAllRegisters() {
817   m_gpr_is_valid = false;
818   m_fpu_is_valid = false;
819 }
820 
821 uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset(
822     const RegisterInfo *reg_info) const {
823   return reg_info->byte_offset - GetGPRSize();
824 }
825 
826 #endif // defined (__arm64__) || defined (__aarch64__)
827