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