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