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