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     uint32_t fpr_offset = CalculateFprOffset(reg_info);
253     assert (fpr_offset < sizeof m_fpr);
254     uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
255     reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, eByteOrderLittle, error);
256 
257     return error;
258 }
259 
260 Error
261 NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
262 {
263     if (!reg_info)
264         return Error ("reg_info NULL");
265 
266     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
267     if (reg_index == LLDB_INVALID_REGNUM)
268         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
269 
270     if (IsGPR(reg_index))
271         return WriteRegisterRaw(reg_index, reg_value);
272 
273     if (IsFPR(reg_index))
274     {
275         // Get pointer to m_fpr variable and set the data to it.
276         uint32_t fpr_offset = CalculateFprOffset(reg_info);
277         assert (fpr_offset < sizeof m_fpr);
278         uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
279         switch (reg_info->byte_size)
280         {
281             case 2:
282                 *(uint16_t *)dst = reg_value.GetAsUInt16();
283                 break;
284             case 4:
285                 *(uint32_t *)dst = reg_value.GetAsUInt32();
286                 break;
287             case 8:
288                 *(uint64_t *)dst = reg_value.GetAsUInt64();
289                 break;
290             default:
291                 assert(false && "Unhandled data size.");
292                 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
293         }
294 
295         Error error = WriteFPR();
296         if (error.Fail())
297             return error;
298 
299         return Error ();
300     }
301 
302     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
303 }
304 
305 Error
306 NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
307 {
308     Error error;
309 
310     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
311     if (!data_sp)
312         return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
313 
314     error = ReadGPR();
315     if (error.Fail())
316         return error;
317 
318     error = ReadFPR();
319     if (error.Fail())
320         return error;
321 
322     uint8_t *dst = data_sp->GetBytes ();
323     if (dst == nullptr)
324     {
325         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
326         return error;
327     }
328 
329     ::memcpy (dst, &m_gpr_arm64, GetGPRSize());
330     dst += GetGPRSize();
331     ::memcpy (dst, &m_fpr, sizeof(m_fpr));
332 
333     return error;
334 }
335 
336 Error
337 NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
338 {
339     Error error;
340 
341     if (!data_sp)
342     {
343         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
344         return error;
345     }
346 
347     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
348     {
349         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
350         return error;
351     }
352 
353 
354     uint8_t *src = data_sp->GetBytes ();
355     if (src == nullptr)
356     {
357         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
358         return error;
359     }
360     ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ());
361 
362     error = WriteGPR();
363     if (error.Fail())
364         return error;
365 
366     src += GetRegisterInfoInterface ().GetGPRSize ();
367     ::memcpy (&m_fpr, src, sizeof(m_fpr));
368 
369     error = WriteFPR();
370     if (error.Fail())
371         return error;
372 
373     return error;
374 }
375 
376 bool
377 NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const
378 {
379     return reg <= m_reg_info.last_gpr;   // GPR's come first.
380 }
381 
382 bool
383 NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const
384 {
385     return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
386 }
387 
388 uint32_t
389 NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
390 {
391     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
392 
393     if (log)
394         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
395 
396     Error error;
397 
398     // Read hardware breakpoint and watchpoint information.
399     error = ReadHardwareDebugInfo ();
400 
401     if (error.Fail())
402         return LLDB_INVALID_INDEX32;
403 
404     uint32_t control_value = 0, bp_index = 0;
405 
406     // Check if size has a valid hardware breakpoint length.
407     if (size != 4)
408         return LLDB_INVALID_INDEX32;  // Invalid size for a AArch64 hardware breakpoint
409 
410     // Check 4-byte alignment for hardware breakpoint target address.
411     if (addr & 0x03)
412         return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
413 
414     // Setup control value
415     control_value = 0;
416     control_value |= ((1 << size) - 1) << 5;
417     control_value |= (2 << 1) | 1;
418 
419     // Iterate over stored hardware breakpoints
420     // Find a free bp_index or update reference count if duplicate.
421     bp_index = LLDB_INVALID_INDEX32;
422     for (uint32_t i = 0; i < m_max_hbp_supported; i++)
423     {
424         if ((m_hbr_regs[i].control & 1) == 0)
425         {
426             bp_index = i;  // Mark last free slot
427         }
428         else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
429         {
430             bp_index = i;  // Mark duplicate index
431             break;  // Stop searching here
432         }
433     }
434 
435      if (bp_index == LLDB_INVALID_INDEX32)
436         return LLDB_INVALID_INDEX32;
437 
438     // Add new or update existing watchpoint
439     if ((m_hbr_regs[bp_index].control & 1) == 0)
440     {
441         m_hbr_regs[bp_index].address = addr;
442         m_hbr_regs[bp_index].control = control_value;
443         m_hbr_regs[bp_index].refcount = 1;
444 
445         // PTRACE call to set corresponding hardware breakpoint register.
446         error = WriteHardwareDebugRegs(eDREGTypeBREAK);
447 
448         if (error.Fail())
449             return LLDB_INVALID_INDEX32;
450     }
451     else
452         m_hbr_regs[bp_index].refcount++;
453 
454     return bp_index;
455 }
456 
457 bool
458 NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx)
459 {
460     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
461 
462     if (log)
463         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
464 
465     Error error;
466 
467     // Read hardware breakpoint and watchpoint information.
468     error = ReadHardwareDebugInfo ();
469 
470     if (error.Fail())
471         return false;
472 
473     if (hw_idx >= m_max_hbp_supported)
474         return false;
475 
476     // Update reference count if multiple references.
477     if (m_hbr_regs[hw_idx].refcount > 1)
478     {
479         m_hbr_regs[hw_idx].refcount--;
480         return true;
481     }
482     else if (m_hbr_regs[hw_idx].refcount == 1)
483     {
484         m_hbr_regs[hw_idx].control &= ~1;
485         m_hbr_regs[hw_idx].address = 0;
486         m_hbr_regs[hw_idx].refcount = 0;
487 
488         // PTRACE call to clear corresponding hardware breakpoint register.
489         WriteHardwareDebugRegs(eDREGTypeBREAK);
490 
491         if (error.Fail())
492             return false;
493 
494         return true;
495     }
496 
497     return false;
498 }
499 
500 uint32_t
501 NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints ()
502 {
503     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
504 
505     if (log)
506         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
507 
508     Error error;
509 
510     // Read hardware breakpoint and watchpoint information.
511     error = ReadHardwareDebugInfo ();
512 
513     if (error.Fail())
514         return LLDB_INVALID_INDEX32;
515 
516     return m_max_hwp_supported;
517 }
518 
519 uint32_t
520 NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
521 {
522     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
523 
524     if (log)
525         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
526 
527     Error error;
528 
529     // Read hardware breakpoint and watchpoint information.
530     error = ReadHardwareDebugInfo ();
531 
532     if (error.Fail())
533         return LLDB_INVALID_INDEX32;
534 
535     uint32_t control_value = 0, wp_index = 0;
536 
537     // Check if we are setting watchpoint other than read/write/access
538     // Also update watchpoint flag to match AArch64 write-read bit configuration.
539     switch (watch_flags)
540     {
541         case 1:
542             watch_flags = 2;
543             break;
544         case 2:
545             watch_flags = 1;
546             break;
547         case 3:
548             break;
549         default:
550             return LLDB_INVALID_INDEX32;
551     }
552 
553     // Check if size has a valid hardware watchpoint length.
554     if (size != 1 && size != 2 && size != 4 && size != 8)
555         return LLDB_INVALID_INDEX32;
556 
557     // Check 8-byte alignment for hardware watchpoint target address.
558     // TODO: Add support for watching un-aligned addresses
559     if (addr & 0x07)
560         return LLDB_INVALID_INDEX32;
561 
562     // Setup control value
563     control_value = watch_flags << 3;
564     control_value |= ((1 << size) - 1) << 5;
565     control_value |= (2 << 1) | 1;
566 
567     // Iterate over stored watchpoints
568     // Find a free wp_index or update reference count if duplicate.
569     wp_index = LLDB_INVALID_INDEX32;
570     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
571     {
572         if ((m_hwp_regs[i].control & 1) == 0)
573         {
574             wp_index = i; // Mark last free slot
575         }
576         else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
577         {
578             wp_index = i; // Mark duplicate index
579             break; // Stop searching here
580         }
581     }
582 
583      if (wp_index == LLDB_INVALID_INDEX32)
584         return LLDB_INVALID_INDEX32;
585 
586     // Add new or update existing watchpoint
587     if ((m_hwp_regs[wp_index].control & 1) == 0)
588     {
589         // Update watchpoint in local cache
590         m_hwp_regs[wp_index].address = addr;
591         m_hwp_regs[wp_index].control = control_value;
592         m_hwp_regs[wp_index].refcount = 1;
593 
594         // PTRACE call to set corresponding watchpoint register.
595         error = WriteHardwareDebugRegs(eDREGTypeWATCH);
596 
597         if (error.Fail())
598             return LLDB_INVALID_INDEX32;
599     }
600     else
601         m_hwp_regs[wp_index].refcount++;
602 
603     return wp_index;
604 }
605 
606 bool
607 NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index)
608 {
609     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
610 
611     if (log)
612         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
613 
614     Error error;
615 
616     // Read hardware breakpoint and watchpoint information.
617     error = ReadHardwareDebugInfo ();
618 
619     if (error.Fail())
620         return false;
621 
622     if (wp_index >= m_max_hwp_supported)
623         return false;
624 
625     // Update reference count if multiple references.
626     if (m_hwp_regs[wp_index].refcount > 1)
627     {
628         m_hwp_regs[wp_index].refcount--;
629         return true;
630     }
631     else if (m_hwp_regs[wp_index].refcount == 1)
632     {
633         // Update watchpoint in local cache
634         m_hwp_regs[wp_index].control &= ~1;
635         m_hwp_regs[wp_index].address = 0;
636         m_hwp_regs[wp_index].refcount = 0;
637 
638         // Ptrace call to update hardware debug registers
639         error = WriteHardwareDebugRegs(eDREGTypeWATCH);
640 
641         if (error.Fail())
642             return false;
643 
644         return true;
645     }
646 
647     return false;
648 }
649 
650 Error
651 NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints ()
652 {
653     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
654 
655     if (log)
656         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
657 
658     Error error;
659 
660     // Read hardware breakpoint and watchpoint information.
661     error = ReadHardwareDebugInfo ();
662 
663     if (error.Fail())
664         return error;
665 
666     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
667     {
668         if (m_hwp_regs[i].control & 0x01)
669         {
670             // Clear watchpoints in local cache
671             m_hwp_regs[i].control &= ~1;
672             m_hwp_regs[i].address = 0;
673             m_hwp_regs[i].refcount = 0;
674 
675             // Ptrace call to update hardware debug registers
676             error = WriteHardwareDebugRegs(eDREGTypeWATCH);
677 
678             if (error.Fail())
679                 return error;
680         }
681     }
682 
683     return Error();
684 }
685 
686 uint32_t
687 NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index)
688 {
689     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
690 
691     if (log)
692         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
693     switch ((m_hwp_regs[wp_index].control >> 5) & 0xff)
694     {
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
708 NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index)
709 {
710     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
711 
712     if (log)
713         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
714 
715     if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
716         return true;
717     else
718         return false;
719 }
720 
721 Error
722 NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
723 {
724     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
725 
726     if (log)
727         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
728 
729     uint32_t watch_size;
730     lldb::addr_t watch_addr;
731 
732     for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
733     {
734         watch_size = GetWatchpointSize (wp_index);
735         watch_addr = m_hwp_regs[wp_index].address;
736 
737         if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
738             && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
739         {
740             return Error();
741         }
742     }
743 
744     wp_index = LLDB_INVALID_INDEX32;
745     return Error();
746 }
747 
748 lldb::addr_t
749 NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index)
750 {
751     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
752 
753     if (log)
754         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
755 
756     if (wp_index >= m_max_hwp_supported)
757         return LLDB_INVALID_ADDRESS;
758 
759     if (WatchpointIsEnabled(wp_index))
760         return m_hwp_regs[wp_index].address;
761     else
762         return LLDB_INVALID_ADDRESS;
763 }
764 
765 Error
766 NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo()
767 {
768     if (!m_refresh_hwdebug_info)
769     {
770         return Error();
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     Error error;
779 
780     ioVec.iov_base = &dreg_state;
781     ioVec.iov_len = sizeof (dreg_state);
782     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
783 
784     if (error.Fail())
785         return error;
786 
787     m_max_hwp_supported = dreg_state.dbg_info & 0xff;
788 
789     regset = NT_ARM_HW_BREAK;
790     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
791 
792     if (error.Fail())
793         return error;
794 
795     m_max_hbp_supported = dreg_state.dbg_info & 0xff;
796     m_refresh_hwdebug_info = false;
797 
798     return error;
799 }
800 
801 Error
802 NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType)
803 {
804     struct iovec ioVec;
805     struct user_hwdebug_state dreg_state;
806     Error error;
807 
808     memset (&dreg_state, 0, sizeof (dreg_state));
809     ioVec.iov_base = &dreg_state;
810     ioVec.iov_len = sizeof (dreg_state);
811 
812     if (hwbType == eDREGTypeWATCH)
813     {
814         hwbType = NT_ARM_HW_WATCH;
815 
816         for (uint32_t i = 0; i < m_max_hwp_supported; i++)
817         {
818             dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
819             dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
820         }
821     }
822     else
823     {
824         hwbType = NT_ARM_HW_BREAK;
825 
826         for (uint32_t i = 0; i < m_max_hbp_supported; i++)
827         {
828             dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address;
829             dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control;
830         }
831     }
832 
833     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &hwbType, &ioVec, ioVec.iov_len);
834 }
835 
836 Error
837 NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset,
838                                                       const char* reg_name,
839                                                       uint32_t size,
840                                                       RegisterValue &value)
841 {
842     Error error;
843     if (offset > sizeof(struct user_pt_regs))
844     {
845         uintptr_t offset = offset - sizeof(struct user_pt_regs);
846         if (offset > sizeof(struct user_fpsimd_state))
847         {
848             error.SetErrorString("invalid offset value");
849             return error;
850         }
851         elf_fpregset_t regs;
852         int regset = NT_FPREGSET;
853         struct iovec ioVec;
854 
855         ioVec.iov_base = &regs;
856         ioVec.iov_len = sizeof regs;
857         error = NativeProcessLinux::PtraceWrapper(
858                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
859         if (error.Success())
860         {
861             ArchSpec arch;
862             if (m_thread.GetProcess()->GetArchitecture(arch))
863                 value.SetBytes((void *)(((unsigned char *)(&regs)) + offset), 16, arch.GetByteOrder());
864             else
865                 error.SetErrorString("failed to get architecture");
866         }
867     }
868     else
869     {
870         elf_gregset_t regs;
871         int regset = NT_PRSTATUS;
872         struct iovec ioVec;
873 
874         ioVec.iov_base = &regs;
875         ioVec.iov_len = sizeof regs;
876         error = NativeProcessLinux::PtraceWrapper(
877                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
878         if (error.Success())
879         {
880             ArchSpec arch;
881             if (m_thread.GetProcess()->GetArchitecture(arch))
882                 value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder());
883             else
884                 error.SetErrorString("failed to get architecture");
885         }
886     }
887     return error;
888 }
889 
890 Error
891 NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset,
892                                                        const char* reg_name,
893                                                        const RegisterValue &value)
894 {
895     Error error;
896     ::pid_t tid = m_thread.GetID();
897     if (offset > sizeof(struct user_pt_regs))
898     {
899         uintptr_t offset = offset - sizeof(struct user_pt_regs);
900         if (offset > sizeof(struct user_fpsimd_state))
901         {
902             error.SetErrorString("invalid offset value");
903             return error;
904         }
905         elf_fpregset_t regs;
906         int regset = NT_FPREGSET;
907         struct iovec ioVec;
908 
909         ioVec.iov_base = &regs;
910         ioVec.iov_len = sizeof regs;
911         error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
912 
913         if (error.Success())
914         {
915             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 16);
916             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
917         }
918     }
919     else
920     {
921         elf_gregset_t regs;
922         int regset = NT_PRSTATUS;
923         struct iovec ioVec;
924 
925         ioVec.iov_base = &regs;
926         ioVec.iov_len = sizeof regs;
927         error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
928         if (error.Success())
929         {
930             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 8);
931             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
932         }
933     }
934     return error;
935 }
936 
937 Error
938 NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size)
939 {
940     int regset = NT_PRSTATUS;
941     struct iovec ioVec;
942     Error error;
943 
944     ioVec.iov_base = buf;
945     ioVec.iov_len = buf_size;
946     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
947 }
948 
949 Error
950 NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size)
951 {
952     int regset = NT_PRSTATUS;
953     struct iovec ioVec;
954     Error error;
955 
956     ioVec.iov_base = buf;
957     ioVec.iov_len = buf_size;
958     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
959 }
960 
961 Error
962 NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size)
963 {
964     int regset = NT_FPREGSET;
965     struct iovec ioVec;
966     Error error;
967 
968     ioVec.iov_base = buf;
969     ioVec.iov_len = buf_size;
970     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
971 }
972 
973 Error
974 NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size)
975 {
976     int regset = NT_FPREGSET;
977     struct iovec ioVec;
978     Error error;
979 
980     ioVec.iov_base = buf;
981     ioVec.iov_len = buf_size;
982     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
983 }
984 
985 uint32_t
986 NativeRegisterContextLinux_arm64::CalculateFprOffset(const RegisterInfo* reg_info) const
987 {
988     return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
989 }
990 
991 #endif // defined (__arm64__) || defined (__aarch64__)
992