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