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