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