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     Error error;
395 
396     // Read hardware breakpoint and watchpoint information.
397     error = ReadHardwareDebugInfo ();
398 
399     if (error.Fail())
400         return LLDB_INVALID_INDEX32;
401 
402     uint32_t control_value = 0, bp_index = 0;
403 
404     // Check if size has a valid hardware breakpoint length.
405     if (size != 4)
406         return LLDB_INVALID_INDEX32;  // Invalid size for a AArch64 hardware breakpoint
407 
408     // Check 4-byte alignment for hardware breakpoint target address.
409     if (addr & 0x03)
410         return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
411 
412     // Setup control value
413     control_value = 0;
414     control_value |= ((1 << size) - 1) << 5;
415     control_value |= (2 << 1) | 1;
416 
417     // Iterate over stored hardware breakpoints
418     // Find a free bp_index or update reference count if duplicate.
419     bp_index = LLDB_INVALID_INDEX32;
420     for (uint32_t i = 0; i < m_max_hbp_supported; i++)
421     {
422         if ((m_hbr_regs[i].control & 1) == 0)
423         {
424             bp_index = i;  // Mark last free slot
425         }
426         else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
427         {
428             bp_index = i;  // Mark duplicate index
429             break;  // Stop searching here
430         }
431     }
432 
433      if (bp_index == LLDB_INVALID_INDEX32)
434         return LLDB_INVALID_INDEX32;
435 
436     // Add new or update existing watchpoint
437     if ((m_hbr_regs[bp_index].control & 1) == 0)
438     {
439         m_hbr_regs[bp_index].address = addr;
440         m_hbr_regs[bp_index].control = control_value;
441         m_hbr_regs[bp_index].refcount = 1;
442 
443         // PTRACE call to set corresponding hardware breakpoint register.
444         error = WriteHardwareDebugRegs(eDREGTypeBREAK);
445 
446         if (error.Fail())
447             return LLDB_INVALID_INDEX32;
448     }
449     else
450         m_hbr_regs[bp_index].refcount++;
451 
452     return bp_index;
453 }
454 
455 bool
456 NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx)
457 {
458     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
459 
460     if (log)
461         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
462 
463     Error error;
464 
465     // Read hardware breakpoint and watchpoint information.
466     error = ReadHardwareDebugInfo ();
467 
468     if (error.Fail())
469         return false;
470 
471     if (hw_idx >= m_max_hbp_supported)
472         return false;
473 
474     // Update reference count if multiple references.
475     if (m_hbr_regs[hw_idx].refcount > 1)
476     {
477         m_hbr_regs[hw_idx].refcount--;
478         return true;
479     }
480     else if (m_hbr_regs[hw_idx].refcount == 1)
481     {
482         m_hbr_regs[hw_idx].control &= ~1;
483         m_hbr_regs[hw_idx].address = 0;
484         m_hbr_regs[hw_idx].refcount = 0;
485 
486         // PTRACE call to clear corresponding hardware breakpoint register.
487         WriteHardwareDebugRegs(eDREGTypeBREAK);
488 
489         if (error.Fail())
490             return false;
491 
492         return true;
493     }
494 
495     return false;
496 }
497 
498 uint32_t
499 NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints ()
500 {
501     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
502 
503     if (log)
504         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
505 
506     Error error;
507 
508     // Read hardware breakpoint and watchpoint information.
509     error = ReadHardwareDebugInfo ();
510 
511     if (error.Fail())
512         return LLDB_INVALID_INDEX32;
513 
514     return m_max_hwp_supported;
515 }
516 
517 uint32_t
518 NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
519 {
520     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
521 
522     if (log)
523         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
524 
525     Error error;
526 
527     // Read hardware breakpoint and watchpoint information.
528     error = ReadHardwareDebugInfo ();
529 
530     if (error.Fail())
531         return LLDB_INVALID_INDEX32;
532 
533     uint32_t control_value = 0, wp_index = 0;
534 
535     // Check if we are setting watchpoint other than read/write/access
536     // Also update watchpoint flag to match AArch64 write-read bit configuration.
537     switch (watch_flags)
538     {
539         case 1:
540             watch_flags = 2;
541             break;
542         case 2:
543             watch_flags = 1;
544             break;
545         case 3:
546             break;
547         default:
548             return LLDB_INVALID_INDEX32;
549     }
550 
551     // Check if size has a valid hardware watchpoint length.
552     if (size != 1 && size != 2 && size != 4 && size != 8)
553         return LLDB_INVALID_INDEX32;
554 
555     // Check 8-byte alignment for hardware watchpoint target address.
556     // TODO: Add support for watching un-aligned addresses
557     if (addr & 0x07)
558         return LLDB_INVALID_INDEX32;
559 
560     // Setup control value
561     control_value = watch_flags << 3;
562     control_value |= ((1 << size) - 1) << 5;
563     control_value |= (2 << 1) | 1;
564 
565     // Iterate over stored watchpoints
566     // Find a free wp_index or update reference count if duplicate.
567     wp_index = LLDB_INVALID_INDEX32;
568     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
569     {
570         if ((m_hwp_regs[i].control & 1) == 0)
571         {
572             wp_index = i; // Mark last free slot
573         }
574         else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
575         {
576             wp_index = i; // Mark duplicate index
577             break; // Stop searching here
578         }
579     }
580 
581      if (wp_index == LLDB_INVALID_INDEX32)
582         return LLDB_INVALID_INDEX32;
583 
584     // Add new or update existing watchpoint
585     if ((m_hwp_regs[wp_index].control & 1) == 0)
586     {
587         // Update watchpoint in local cache
588         m_hwp_regs[wp_index].address = addr;
589         m_hwp_regs[wp_index].control = control_value;
590         m_hwp_regs[wp_index].refcount = 1;
591 
592         // PTRACE call to set corresponding watchpoint register.
593         error = WriteHardwareDebugRegs(eDREGTypeWATCH);
594 
595         if (error.Fail())
596             return LLDB_INVALID_INDEX32;
597     }
598     else
599         m_hwp_regs[wp_index].refcount++;
600 
601     return wp_index;
602 }
603 
604 bool
605 NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index)
606 {
607     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
608 
609     if (log)
610         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
611 
612     Error error;
613 
614     // Read hardware breakpoint and watchpoint information.
615     error = ReadHardwareDebugInfo ();
616 
617     if (error.Fail())
618         return false;
619 
620     if (wp_index >= m_max_hwp_supported)
621         return false;
622 
623     // Update reference count if multiple references.
624     if (m_hwp_regs[wp_index].refcount > 1)
625     {
626         m_hwp_regs[wp_index].refcount--;
627         return true;
628     }
629     else if (m_hwp_regs[wp_index].refcount == 1)
630     {
631         // Update watchpoint in local cache
632         m_hwp_regs[wp_index].control &= ~1;
633         m_hwp_regs[wp_index].address = 0;
634         m_hwp_regs[wp_index].refcount = 0;
635 
636         // Ptrace call to update hardware debug registers
637         error = WriteHardwareDebugRegs(eDREGTypeWATCH);
638 
639         if (error.Fail())
640             return false;
641 
642         return true;
643     }
644 
645     return false;
646 }
647 
648 Error
649 NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints ()
650 {
651     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
652 
653     if (log)
654         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
655 
656     Error error;
657 
658     // Read hardware breakpoint and watchpoint information.
659     error = ReadHardwareDebugInfo ();
660 
661     if (error.Fail())
662         return error;
663 
664     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
665     {
666         if (m_hwp_regs[i].control & 0x01)
667         {
668             // Clear watchpoints in local cache
669             m_hwp_regs[i].control &= ~1;
670             m_hwp_regs[i].address = 0;
671             m_hwp_regs[i].refcount = 0;
672 
673             // Ptrace call to update hardware debug registers
674             error = WriteHardwareDebugRegs(eDREGTypeWATCH);
675 
676             if (error.Fail())
677                 return error;
678         }
679     }
680 
681     return Error();
682 }
683 
684 uint32_t
685 NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index)
686 {
687     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
688 
689     if (log)
690         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
691     switch ((m_hwp_regs[wp_index].control >> 5) & 0xff)
692     {
693         case 0x01:
694             return 1;
695         case 0x03:
696             return 2;
697         case 0x0f:
698             return 4;
699         case 0xff:
700             return 8;
701         default:
702             return 0;
703     }
704 }
705 bool
706 NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index)
707 {
708     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
709 
710     if (log)
711         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
712 
713     if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
714         return true;
715     else
716         return false;
717 }
718 
719 Error
720 NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
721 {
722     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
723 
724     if (log)
725         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
726 
727     uint32_t watch_size;
728     lldb::addr_t watch_addr;
729 
730     for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
731     {
732         watch_size = GetWatchpointSize (wp_index);
733         watch_addr = m_hwp_regs[wp_index].address;
734 
735         if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
736             && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
737         {
738             return Error();
739         }
740     }
741 
742     wp_index = LLDB_INVALID_INDEX32;
743     return Error();
744 }
745 
746 lldb::addr_t
747 NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index)
748 {
749     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
750 
751     if (log)
752         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
753 
754     if (wp_index >= m_max_hwp_supported)
755         return LLDB_INVALID_ADDRESS;
756 
757     if (WatchpointIsEnabled(wp_index))
758         return m_hwp_regs[wp_index].address;
759     else
760         return LLDB_INVALID_ADDRESS;
761 }
762 
763 Error
764 NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo()
765 {
766     if (!m_refresh_hwdebug_info)
767     {
768         return Error();
769     }
770 
771     ::pid_t tid = m_thread.GetID();
772 
773     int regset = NT_ARM_HW_WATCH;
774     struct iovec ioVec;
775     struct user_hwdebug_state dreg_state;
776     Error error;
777 
778     ioVec.iov_base = &dreg_state;
779     ioVec.iov_len = sizeof (dreg_state);
780     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
781 
782     if (error.Fail())
783         return error;
784 
785     m_max_hwp_supported = dreg_state.dbg_info & 0xff;
786 
787     regset = NT_ARM_HW_BREAK;
788     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
789 
790     if (error.Fail())
791         return error;
792 
793     m_max_hbp_supported = dreg_state.dbg_info & 0xff;
794     m_refresh_hwdebug_info = false;
795 
796     return error;
797 }
798 
799 Error
800 NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType)
801 {
802     struct iovec ioVec;
803     struct user_hwdebug_state dreg_state;
804     Error error;
805 
806     memset (&dreg_state, 0, sizeof (dreg_state));
807     ioVec.iov_base = &dreg_state;
808     ioVec.iov_len = sizeof (dreg_state);
809 
810     if (hwbType == eDREGTypeWATCH)
811     {
812         hwbType = NT_ARM_HW_WATCH;
813 
814         for (uint32_t i = 0; i < m_max_hwp_supported; i++)
815         {
816             dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
817             dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
818         }
819     }
820     else
821     {
822         hwbType = NT_ARM_HW_BREAK;
823 
824         for (uint32_t i = 0; i < m_max_hbp_supported; i++)
825         {
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(), &hwbType, &ioVec, ioVec.iov_len);
832 }
833 
834 Error
835 NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset,
836                                                       const char* reg_name,
837                                                       uint32_t size,
838                                                       RegisterValue &value)
839 {
840     Error error;
841     if (offset > sizeof(struct user_pt_regs))
842     {
843         uintptr_t offset = offset - sizeof(struct user_pt_regs);
844         if (offset > sizeof(struct user_fpsimd_state))
845         {
846             error.SetErrorString("invalid offset value");
847             return error;
848         }
849         elf_fpregset_t regs;
850         int regset = NT_FPREGSET;
851         struct iovec ioVec;
852 
853         ioVec.iov_base = &regs;
854         ioVec.iov_len = sizeof regs;
855         error = NativeProcessLinux::PtraceWrapper(
856                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
857         if (error.Success())
858         {
859             ArchSpec arch;
860             if (m_thread.GetProcess()->GetArchitecture(arch))
861                 value.SetBytes((void *)(((unsigned char *)(&regs)) + offset), 16, arch.GetByteOrder());
862             else
863                 error.SetErrorString("failed to get architecture");
864         }
865     }
866     else
867     {
868         elf_gregset_t regs;
869         int regset = NT_PRSTATUS;
870         struct iovec ioVec;
871 
872         ioVec.iov_base = &regs;
873         ioVec.iov_len = sizeof regs;
874         error = NativeProcessLinux::PtraceWrapper(
875                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
876         if (error.Success())
877         {
878             ArchSpec arch;
879             if (m_thread.GetProcess()->GetArchitecture(arch))
880                 value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder());
881             else
882                 error.SetErrorString("failed to get architecture");
883         }
884     }
885     return error;
886 }
887 
888 Error
889 NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset,
890                                                        const char* reg_name,
891                                                        const RegisterValue &value)
892 {
893     Error error;
894     ::pid_t tid = m_thread.GetID();
895     if (offset > sizeof(struct user_pt_regs))
896     {
897         uintptr_t offset = offset - sizeof(struct user_pt_regs);
898         if (offset > sizeof(struct user_fpsimd_state))
899         {
900             error.SetErrorString("invalid offset value");
901             return error;
902         }
903         elf_fpregset_t regs;
904         int regset = NT_FPREGSET;
905         struct iovec ioVec;
906 
907         ioVec.iov_base = &regs;
908         ioVec.iov_len = sizeof regs;
909         error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
910 
911         if (error.Success())
912         {
913             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 16);
914             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
915         }
916     }
917     else
918     {
919         elf_gregset_t regs;
920         int regset = NT_PRSTATUS;
921         struct iovec ioVec;
922 
923         ioVec.iov_base = &regs;
924         ioVec.iov_len = sizeof regs;
925         error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
926         if (error.Success())
927         {
928             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 8);
929             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
930         }
931     }
932     return error;
933 }
934 
935 Error
936 NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size)
937 {
938     int regset = NT_PRSTATUS;
939     struct iovec ioVec;
940     Error error;
941 
942     ioVec.iov_base = buf;
943     ioVec.iov_len = buf_size;
944     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
945 }
946 
947 Error
948 NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size)
949 {
950     int regset = NT_PRSTATUS;
951     struct iovec ioVec;
952     Error error;
953 
954     ioVec.iov_base = buf;
955     ioVec.iov_len = buf_size;
956     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
957 }
958 
959 Error
960 NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size)
961 {
962     int regset = NT_FPREGSET;
963     struct iovec ioVec;
964     Error error;
965 
966     ioVec.iov_base = buf;
967     ioVec.iov_len = buf_size;
968     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
969 }
970 
971 Error
972 NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size)
973 {
974     int regset = NT_FPREGSET;
975     struct iovec ioVec;
976     Error error;
977 
978     ioVec.iov_base = buf;
979     ioVec.iov_len = buf_size;
980     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
981 }
982 
983 #endif // defined (__arm64__) || defined (__aarch64__)
984