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 
570     // Check if we are setting watchpoint other than read/write/access
571     // Also update watchpoint flag to match AArch64 write-read bit configuration.
572     switch (watch_flags)
573     {
574         case 1:
575             watch_flags = 2;
576             break;
577         case 2:
578             watch_flags = 1;
579             break;
580         case 3:
581             break;
582         default:
583             return LLDB_INVALID_INDEX32;
584     }
585 
586     // Check if size has a valid hardware watchpoint length.
587     if (size != 1 && size != 2 && size != 4 && size != 8)
588         return LLDB_INVALID_INDEX32;
589 
590     // Check 8-byte alignment for hardware watchpoint target address.
591     // TODO: Add support for watching un-aligned addresses
592     if (addr & 0x07)
593         return LLDB_INVALID_INDEX32;
594 
595     // Setup control value
596     control_value = watch_flags << 3;
597     control_value |= ((1 << size) - 1) << 5;
598     control_value |= (2 << 1) | 1;
599 
600     // Iterate over stored watchpoints
601     // Find a free wp_index or update reference count if duplicate.
602     wp_index = LLDB_INVALID_INDEX32;
603     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
604     {
605         if ((m_hwp_regs[i].control & 1) == 0)
606         {
607             wp_index = i; // Mark last free slot
608         }
609         else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
610         {
611             wp_index = i; // Mark duplicate index
612             break; // Stop searching here
613         }
614     }
615 
616      if (wp_index == LLDB_INVALID_INDEX32)
617         return LLDB_INVALID_INDEX32;
618 
619     // Add new or update existing watchpoint
620     if ((m_hwp_regs[wp_index].control & 1) == 0)
621     {
622         // Update watchpoint in local cache
623         m_hwp_regs[wp_index].address = addr;
624         m_hwp_regs[wp_index].control = control_value;
625         m_hwp_regs[wp_index].refcount = 1;
626 
627         // PTRACE call to set corresponding watchpoint register.
628         error = WriteHardwareDebugRegs(eDREGTypeWATCH);
629 
630         if (error.Fail())
631         {
632             m_hwp_regs[wp_index].address = 0;
633             m_hwp_regs[wp_index].control &= ~1;
634             m_hwp_regs[wp_index].refcount = 0;
635 
636             return LLDB_INVALID_INDEX32;
637         }
638     }
639     else
640         m_hwp_regs[wp_index].refcount++;
641 
642     return wp_index;
643 }
644 
645 bool
646 NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index)
647 {
648     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
649 
650     if (log)
651         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
652 
653     Error error;
654 
655     // Read hardware breakpoint and watchpoint information.
656     error = ReadHardwareDebugInfo ();
657 
658     if (error.Fail())
659         return false;
660 
661     if (wp_index >= m_max_hwp_supported)
662         return false;
663 
664     // Update reference count if multiple references.
665     if (m_hwp_regs[wp_index].refcount > 1)
666     {
667         m_hwp_regs[wp_index].refcount--;
668         return true;
669     }
670     else if (m_hwp_regs[wp_index].refcount == 1)
671     {
672         // Create a backup we can revert to in case of failure.
673         lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
674         uint32_t tempControl = m_hwp_regs[wp_index].control;
675         uint32_t tempRefCount = m_hwp_regs[wp_index].refcount;
676 
677         // Update watchpoint in local cache
678         m_hwp_regs[wp_index].control &= ~1;
679         m_hwp_regs[wp_index].address = 0;
680         m_hwp_regs[wp_index].refcount = 0;
681 
682         // Ptrace call to update hardware debug registers
683         error = WriteHardwareDebugRegs(eDREGTypeWATCH);
684 
685         if (error.Fail())
686         {
687             m_hwp_regs[wp_index].control = tempControl;
688             m_hwp_regs[wp_index].address = tempAddr;
689             m_hwp_regs[wp_index].refcount = tempRefCount;
690 
691             return false;
692         }
693 
694         return true;
695     }
696 
697     return false;
698 }
699 
700 Error
701 NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints ()
702 {
703     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
704 
705     if (log)
706         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
707 
708     Error error;
709 
710     // Read hardware breakpoint and watchpoint information.
711     error = ReadHardwareDebugInfo ();
712 
713     if (error.Fail())
714         return error;
715 
716     lldb::addr_t tempAddr = 0;
717     uint32_t tempControl = 0, tempRefCount = 0;
718 
719     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
720     {
721         if (m_hwp_regs[i].control & 0x01)
722         {
723             // Create a backup we can revert to in case of failure.
724             tempAddr = m_hwp_regs[i].address;
725             tempControl = m_hwp_regs[i].control;
726             tempRefCount = m_hwp_regs[i].refcount;
727 
728             // Clear watchpoints in local cache
729             m_hwp_regs[i].control &= ~1;
730             m_hwp_regs[i].address = 0;
731             m_hwp_regs[i].refcount = 0;
732 
733             // Ptrace call to update hardware debug registers
734             error = WriteHardwareDebugRegs(eDREGTypeWATCH);
735 
736             if (error.Fail())
737             {
738                 m_hwp_regs[i].control = tempControl;
739                 m_hwp_regs[i].address = tempAddr;
740                 m_hwp_regs[i].refcount = tempRefCount;
741 
742                 return error;
743             }
744         }
745     }
746 
747     return Error();
748 }
749 
750 uint32_t
751 NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index)
752 {
753     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
754 
755     if (log)
756         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
757     switch ((m_hwp_regs[wp_index].control >> 5) & 0xff)
758     {
759         case 0x01:
760             return 1;
761         case 0x03:
762             return 2;
763         case 0x0f:
764             return 4;
765         case 0xff:
766             return 8;
767         default:
768             return 0;
769     }
770 }
771 bool
772 NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index)
773 {
774     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
775 
776     if (log)
777         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
778 
779     if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
780         return true;
781     else
782         return false;
783 }
784 
785 Error
786 NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
787 {
788     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
789 
790     if (log)
791         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
792 
793     uint32_t watch_size;
794     lldb::addr_t watch_addr;
795 
796     for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
797     {
798         watch_size = GetWatchpointSize (wp_index);
799         watch_addr = m_hwp_regs[wp_index].address;
800 
801         if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
802             && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
803         {
804             return Error();
805         }
806     }
807 
808     wp_index = LLDB_INVALID_INDEX32;
809     return Error();
810 }
811 
812 lldb::addr_t
813 NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index)
814 {
815     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
816 
817     if (log)
818         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
819 
820     if (wp_index >= m_max_hwp_supported)
821         return LLDB_INVALID_ADDRESS;
822 
823     if (WatchpointIsEnabled(wp_index))
824         return m_hwp_regs[wp_index].address;
825     else
826         return LLDB_INVALID_ADDRESS;
827 }
828 
829 Error
830 NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo()
831 {
832     if (!m_refresh_hwdebug_info)
833     {
834         return Error();
835     }
836 
837     ::pid_t tid = m_thread.GetID();
838 
839     int regset = NT_ARM_HW_WATCH;
840     struct iovec ioVec;
841     struct user_hwdebug_state dreg_state;
842     Error error;
843 
844     ioVec.iov_base = &dreg_state;
845     ioVec.iov_len = sizeof (dreg_state);
846     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
847 
848     if (error.Fail())
849         return error;
850 
851     m_max_hwp_supported = dreg_state.dbg_info & 0xff;
852 
853     regset = NT_ARM_HW_BREAK;
854     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, ioVec.iov_len);
855 
856     if (error.Fail())
857         return error;
858 
859     m_max_hbp_supported = dreg_state.dbg_info & 0xff;
860     m_refresh_hwdebug_info = false;
861 
862     return error;
863 }
864 
865 Error
866 NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType)
867 {
868     struct iovec ioVec;
869     struct user_hwdebug_state dreg_state;
870     Error error;
871 
872     memset (&dreg_state, 0, sizeof (dreg_state));
873     ioVec.iov_base = &dreg_state;
874 
875     if (hwbType == eDREGTypeWATCH)
876     {
877         hwbType = NT_ARM_HW_WATCH;
878         ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad)
879                 + (sizeof (dreg_state.dbg_regs [0]) * m_max_hwp_supported);
880 
881         for (uint32_t i = 0; i < m_max_hwp_supported; i++)
882         {
883             dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
884             dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
885         }
886     }
887     else
888     {
889         hwbType = NT_ARM_HW_BREAK;
890         ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad)
891                 + (sizeof (dreg_state.dbg_regs [0]) * m_max_hbp_supported);
892 
893         for (uint32_t i = 0; i < m_max_hbp_supported; i++)
894         {
895             dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address;
896             dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control;
897         }
898     }
899 
900     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &hwbType, &ioVec, ioVec.iov_len);
901 }
902 
903 Error
904 NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset,
905                                                       const char* reg_name,
906                                                       uint32_t size,
907                                                       RegisterValue &value)
908 {
909     Error error;
910     if (offset > sizeof(struct user_pt_regs))
911     {
912         uintptr_t offset = offset - sizeof(struct user_pt_regs);
913         if (offset > sizeof(struct user_fpsimd_state))
914         {
915             error.SetErrorString("invalid offset value");
916             return error;
917         }
918         elf_fpregset_t regs;
919         int regset = NT_FPREGSET;
920         struct iovec ioVec;
921 
922         ioVec.iov_base = &regs;
923         ioVec.iov_len = sizeof regs;
924         error = NativeProcessLinux::PtraceWrapper(
925                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
926         if (error.Success())
927         {
928             ArchSpec arch;
929             if (m_thread.GetProcess()->GetArchitecture(arch))
930                 value.SetBytes((void *)(((unsigned char *)(&regs)) + offset), 16, arch.GetByteOrder());
931             else
932                 error.SetErrorString("failed to get architecture");
933         }
934     }
935     else
936     {
937         elf_gregset_t regs;
938         int regset = NT_PRSTATUS;
939         struct iovec ioVec;
940 
941         ioVec.iov_base = &regs;
942         ioVec.iov_len = sizeof regs;
943         error = NativeProcessLinux::PtraceWrapper(
944                 PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
945         if (error.Success())
946         {
947             ArchSpec arch;
948             if (m_thread.GetProcess()->GetArchitecture(arch))
949                 value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder());
950             else
951                 error.SetErrorString("failed to get architecture");
952         }
953     }
954     return error;
955 }
956 
957 Error
958 NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset,
959                                                        const char* reg_name,
960                                                        const RegisterValue &value)
961 {
962     Error error;
963     ::pid_t tid = m_thread.GetID();
964     if (offset > sizeof(struct user_pt_regs))
965     {
966         uintptr_t offset = offset - sizeof(struct user_pt_regs);
967         if (offset > sizeof(struct user_fpsimd_state))
968         {
969             error.SetErrorString("invalid offset value");
970             return error;
971         }
972         elf_fpregset_t regs;
973         int regset = NT_FPREGSET;
974         struct iovec ioVec;
975 
976         ioVec.iov_base = &regs;
977         ioVec.iov_len = sizeof regs;
978         error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
979 
980         if (error.Success())
981         {
982             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 16);
983             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
984         }
985     }
986     else
987     {
988         elf_gregset_t regs;
989         int regset = NT_PRSTATUS;
990         struct iovec ioVec;
991 
992         ioVec.iov_base = &regs;
993         ioVec.iov_len = sizeof regs;
994         error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset, &ioVec, sizeof regs);
995         if (error.Success())
996         {
997             ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(), 8);
998             error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset, &ioVec, sizeof regs);
999         }
1000     }
1001     return error;
1002 }
1003 
1004 Error
1005 NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size)
1006 {
1007     int regset = NT_PRSTATUS;
1008     struct iovec ioVec;
1009     Error error;
1010 
1011     ioVec.iov_base = buf;
1012     ioVec.iov_len = buf_size;
1013     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
1014 }
1015 
1016 Error
1017 NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size)
1018 {
1019     int regset = NT_PRSTATUS;
1020     struct iovec ioVec;
1021     Error error;
1022 
1023     ioVec.iov_base = buf;
1024     ioVec.iov_len = buf_size;
1025     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
1026 }
1027 
1028 Error
1029 NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size)
1030 {
1031     int regset = NT_FPREGSET;
1032     struct iovec ioVec;
1033     Error error;
1034 
1035     ioVec.iov_base = buf;
1036     ioVec.iov_len = buf_size;
1037     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
1038 }
1039 
1040 Error
1041 NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size)
1042 {
1043     int regset = NT_FPREGSET;
1044     struct iovec ioVec;
1045     Error error;
1046 
1047     ioVec.iov_base = buf;
1048     ioVec.iov_len = buf_size;
1049     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &regset, &ioVec, buf_size);
1050 }
1051 
1052 uint32_t
1053 NativeRegisterContextLinux_arm64::CalculateFprOffset(const RegisterInfo* reg_info) const
1054 {
1055     return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
1056 }
1057 
1058 #endif // defined (__arm64__) || defined (__aarch64__)
1059