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 #include "NativeRegisterContextLinux_arm64.h"
11 
12 #include "lldb/lldb-private-forward.h"
13 #include "lldb/Core/DataBufferHeap.h"
14 #include "lldb/Core/Error.h"
15 #include "lldb/Core/StreamString.h"
16 #include "lldb/Core/RegisterValue.h"
17 #include "lldb/Host/common/NativeProcessProtocol.h"
18 #include "lldb/Host/common/NativeThreadProtocol.h"
19 #include "Plugins/Process/Linux/NativeProcessLinux.h"
20 #include "lldb/Core/Log.h"
21 
22 #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr))
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 using namespace lldb_private::process_linux;
27 
28 // ARM64 general purpose registers.
29 static const uint32_t g_gpr_regnums_arm64[] =
30 {
31     gpr_x0_arm64,
32     gpr_x1_arm64,
33     gpr_x2_arm64,
34     gpr_x3_arm64,
35     gpr_x4_arm64,
36     gpr_x5_arm64,
37     gpr_x6_arm64,
38     gpr_x7_arm64,
39     gpr_x8_arm64,
40     gpr_x9_arm64,
41     gpr_x10_arm64,
42     gpr_x11_arm64,
43     gpr_x12_arm64,
44     gpr_x13_arm64,
45     gpr_x14_arm64,
46     gpr_x15_arm64,
47     gpr_x16_arm64,
48     gpr_x17_arm64,
49     gpr_x18_arm64,
50     gpr_x19_arm64,
51     gpr_x20_arm64,
52     gpr_x21_arm64,
53     gpr_x22_arm64,
54     gpr_x23_arm64,
55     gpr_x24_arm64,
56     gpr_x25_arm64,
57     gpr_x26_arm64,
58     gpr_x27_arm64,
59     gpr_x28_arm64,
60     gpr_fp_arm64,
61     gpr_lr_arm64,
62     gpr_sp_arm64,
63     gpr_pc_arm64,
64     gpr_cpsr_arm64,
65     LLDB_INVALID_REGNUM // register sets need to end with this flag
66 };
67 static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \
68               "g_gpr_regnums_arm64 has wrong number of register infos");
69 
70 // ARM64 floating point registers.
71 static const uint32_t g_fpu_regnums_arm64[] =
72 {
73     fpu_v0_arm64,
74     fpu_v1_arm64,
75     fpu_v2_arm64,
76     fpu_v3_arm64,
77     fpu_v4_arm64,
78     fpu_v5_arm64,
79     fpu_v6_arm64,
80     fpu_v7_arm64,
81     fpu_v8_arm64,
82     fpu_v9_arm64,
83     fpu_v10_arm64,
84     fpu_v11_arm64,
85     fpu_v12_arm64,
86     fpu_v13_arm64,
87     fpu_v14_arm64,
88     fpu_v15_arm64,
89     fpu_v16_arm64,
90     fpu_v17_arm64,
91     fpu_v18_arm64,
92     fpu_v19_arm64,
93     fpu_v20_arm64,
94     fpu_v21_arm64,
95     fpu_v22_arm64,
96     fpu_v23_arm64,
97     fpu_v24_arm64,
98     fpu_v25_arm64,
99     fpu_v26_arm64,
100     fpu_v27_arm64,
101     fpu_v28_arm64,
102     fpu_v29_arm64,
103     fpu_v30_arm64,
104     fpu_v31_arm64,
105     fpu_fpsr_arm64,
106     fpu_fpcr_arm64,
107     LLDB_INVALID_REGNUM // register sets need to end with this flag
108 };
109 static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \
110               "g_fpu_regnums_arm64 has wrong number of register infos");
111 
112 namespace {
113     // Number of register sets provided by this context.
114     enum
115     {
116         k_num_register_sets = 2
117     };
118 }
119 
120 // Register sets for ARM64.
121 static const RegisterSet
122 g_reg_sets_arm64[k_num_register_sets] =
123 {
124     { "General Purpose Registers",  "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 },
125     { "Floating Point Registers",   "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 }
126 };
127 
128 NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (
129         NativeThreadProtocol &native_thread,
130         uint32_t concrete_frame_idx,
131         RegisterInfoInterface *reg_info_interface_p) :
132     NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p)
133 {
134     switch (reg_info_interface_p->m_target_arch.GetMachine())
135     {
136         case llvm::Triple::aarch64:
137             m_reg_info.num_registers     = k_num_registers_arm64;
138             m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64;
139             m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64;
140             m_reg_info.last_gpr          = k_last_gpr_arm64;
141             m_reg_info.first_fpr         = k_first_fpr_arm64;
142             m_reg_info.last_fpr          = k_last_fpr_arm64;
143             m_reg_info.first_fpr_v       = fpu_v0_arm64;
144             m_reg_info.last_fpr_v        = fpu_v31_arm64;
145             m_reg_info.gpr_flags         = gpr_cpsr_arm64;
146             break;
147         default:
148             assert(false && "Unhandled target architecture.");
149             break;
150     }
151 
152     ::memset(&m_fpr, 0, sizeof (m_fpr));
153     ::memset(&m_gpr_arm64, 0, sizeof (m_gpr_arm64));
154     ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs));
155 
156     // 16 is just a maximum value, query hardware for actual watchpoint count
157     m_max_hwp_supported = 16;
158     m_max_hbp_supported = 16;
159     m_refresh_hwdebug_info = true;
160 }
161 
162 uint32_t
163 NativeRegisterContextLinux_arm64::GetRegisterSetCount () const
164 {
165     return k_num_register_sets;
166 }
167 
168 const RegisterSet *
169 NativeRegisterContextLinux_arm64::GetRegisterSet (uint32_t set_index) const
170 {
171     if (set_index < k_num_register_sets)
172         return &g_reg_sets_arm64[set_index];
173 
174     return nullptr;
175 }
176 
177 Error
178 NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
179 {
180     Error error;
181 
182     if (!reg_info)
183     {
184         error.SetErrorString ("reg_info NULL");
185         return error;
186     }
187 
188     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
189 
190     if (IsFPR(reg))
191     {
192         if (!ReadFPR())
193         {
194             error.SetErrorString ("failed to read floating point register");
195             return error;
196         }
197     }
198     else
199     {
200         uint32_t full_reg = reg;
201         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
202 
203         if (is_subreg)
204         {
205             // Read the full aligned 64-bit register.
206             full_reg = reg_info->invalidate_regs[0];
207         }
208 
209         error = ReadRegisterRaw(full_reg, reg_value);
210 
211         if (error.Success ())
212         {
213             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
214             if (is_subreg && (reg_info->byte_offset & 0x1))
215                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
216 
217             // If our return byte size was greater than the return value reg size, then
218             // use the type specified by reg_info rather than the uint64_t default
219             if (reg_value.GetByteSize() > reg_info->byte_size)
220                 reg_value.SetType(reg_info);
221         }
222         return error;
223     }
224 
225     // Get pointer to m_fpr variable and set the data from it.
226     assert (reg_info->byte_offset < sizeof m_fpr);
227     uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
228     switch (reg_info->byte_size)
229     {
230         case 2:
231             reg_value.SetUInt16(*(uint16_t *)src);
232             break;
233         case 4:
234             reg_value.SetUInt32(*(uint32_t *)src);
235             break;
236         case 8:
237             reg_value.SetUInt64(*(uint64_t *)src);
238             break;
239         default:
240             assert(false && "Unhandled data size.");
241             error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
242             break;
243     }
244 
245     return error;
246 }
247 
248 Error
249 NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
250 {
251     if (!reg_info)
252         return Error ("reg_info NULL");
253 
254     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
255     if (reg_index == LLDB_INVALID_REGNUM)
256         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
257 
258     if (IsGPR(reg_index))
259         return WriteRegisterRaw(reg_index, reg_value);
260 
261     if (IsFPR(reg_index))
262     {
263         // Get pointer to m_fpr variable and set the data to it.
264         assert (reg_info->byte_offset < sizeof(m_fpr));
265         uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
266         switch (reg_info->byte_size)
267         {
268             case 2:
269                 *(uint16_t *)dst = reg_value.GetAsUInt16();
270                 break;
271             case 4:
272                 *(uint32_t *)dst = reg_value.GetAsUInt32();
273                 break;
274             case 8:
275                 *(uint64_t *)dst = reg_value.GetAsUInt64();
276                 break;
277             default:
278                 assert(false && "Unhandled data size.");
279                 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
280         }
281 
282         if (!WriteFPR())
283         {
284             return Error ("NativeRegisterContextLinux_arm64::WriteRegister: WriteFPR failed");
285         }
286 
287         return Error ();
288     }
289 
290     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
291 }
292 
293 Error
294 NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
295 {
296     Error error;
297 
298     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
299     if (!data_sp)
300         return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
301 
302     if (!ReadGPR ())
303     {
304         error.SetErrorString ("ReadGPR() failed");
305         return error;
306     }
307 
308     if (!ReadFPR ())
309     {
310         error.SetErrorString ("ReadFPR() failed");
311         return error;
312     }
313 
314     uint8_t *dst = data_sp->GetBytes ();
315     if (dst == nullptr)
316     {
317         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
318         return error;
319     }
320 
321     ::memcpy (dst, &m_gpr_arm64, GetGPRSize());
322     dst += GetGPRSize();
323     ::memcpy (dst, &m_fpr, sizeof(m_fpr));
324 
325     return error;
326 }
327 
328 Error
329 NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
330 {
331     Error error;
332 
333     if (!data_sp)
334     {
335         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
336         return error;
337     }
338 
339     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
340     {
341         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
342         return error;
343     }
344 
345 
346     uint8_t *src = data_sp->GetBytes ();
347     if (src == nullptr)
348     {
349         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
350         return error;
351     }
352     ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ());
353 
354     if (!WriteGPR ())
355     {
356         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__);
357         return error;
358     }
359 
360     src += GetRegisterInfoInterface ().GetGPRSize ();
361     ::memcpy (&m_fpr, src, sizeof(m_fpr));
362 
363     if (!WriteFPR ())
364     {
365         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__);
366         return error;
367     }
368 
369     return error;
370 }
371 
372 Error
373 NativeRegisterContextLinux_arm64::WriteRegisterRaw (uint32_t reg_index, const RegisterValue &reg_value)
374 {
375     Error error;
376 
377     uint32_t reg_to_write = reg_index;
378     RegisterValue value_to_write = reg_value;
379 
380     // Check if this is a subregister of a full register.
381     const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
382     if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
383     {
384         RegisterValue full_value;
385         uint32_t full_reg = reg_info->invalidate_regs[0];
386         const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
387 
388         // Read the full register.
389         error = ReadRegister(full_reg_info, full_value);
390         if (error.Fail ())
391             return error;
392 
393         lldb::ByteOrder byte_order = GetByteOrder();
394         uint8_t dst[RegisterValue::kMaxRegisterByteSize];
395 
396         // Get the bytes for the full register.
397         const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
398                                                                dst,
399                                                                sizeof(dst),
400                                                                byte_order,
401                                                                error);
402         if (error.Success() && dest_size)
403         {
404             uint8_t src[RegisterValue::kMaxRegisterByteSize];
405 
406             // Get the bytes for the source data.
407             const uint32_t src_size = reg_value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
408             if (error.Success() && src_size && (src_size < dest_size))
409             {
410                 // Copy the src bytes to the destination.
411                 memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
412                 // Set this full register as the value to write.
413                 value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
414                 value_to_write.SetType(full_reg_info);
415                 reg_to_write = full_reg;
416             }
417         }
418     }
419 
420     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
421     if (!process_sp)
422     {
423         error.SetErrorString ("NativeProcessProtocol is NULL");
424         return error;
425     }
426 
427     const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write);
428     assert (register_to_write_info_p && "register to write does not have valid RegisterInfo");
429     if (!register_to_write_info_p)
430     {
431         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_arm64::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
432         return error;
433     }
434 
435     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
436     return process_p->WriteRegisterValue(m_thread.GetID(),
437                                          register_to_write_info_p->byte_offset,
438                                          register_to_write_info_p->name,
439                                          value_to_write);
440 }
441 
442 Error
443 NativeRegisterContextLinux_arm64::ReadRegisterRaw (uint32_t reg_index, RegisterValue &reg_value)
444 {
445     Error error;
446     const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index);
447     if (!reg_info)
448     {
449         error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index);
450         return error;
451     }
452 
453     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
454     if (!process_sp)
455     {
456         error.SetErrorString ("NativeProcessProtocol is NULL");
457         return error;
458     }
459 
460     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
461     return process_p->ReadRegisterValue(m_thread.GetID(),
462                                         reg_info->byte_offset,
463                                         reg_info->name,
464                                         reg_info->byte_size,
465                                         reg_value);
466 }
467 
468 bool
469 NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const
470 {
471     return reg <= m_reg_info.last_gpr;   // GPR's come first.
472 }
473 
474 bool
475 NativeRegisterContextLinux_arm64::ReadGPR()
476 {
477     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
478     if (!process_sp)
479         return false;
480     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
481 
482     return process_p->ReadGPR (m_thread.GetID (), &m_gpr_arm64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
483 }
484 
485 bool
486 NativeRegisterContextLinux_arm64::WriteGPR()
487 {
488     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
489     if (!process_sp)
490         return false;
491     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
492 
493     return process_p->WriteGPR (m_thread.GetID (), &m_gpr_arm64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
494 }
495 
496 bool
497 NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const
498 {
499     return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
500 }
501 
502 bool
503 NativeRegisterContextLinux_arm64::ReadFPR ()
504 {
505     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
506     if (!process_sp)
507         return false;
508 
509     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
510     return process_p->ReadFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
511 }
512 
513 bool
514 NativeRegisterContextLinux_arm64::WriteFPR ()
515 {
516     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
517     if (!process_sp)
518         return false;
519 
520     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
521     return process_p->WriteFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
522 }
523 
524 lldb::ByteOrder
525 NativeRegisterContextLinux_arm64::GetByteOrder() const
526 {
527     // Get the target process whose privileged thread was used for the register read.
528     lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
529 
530     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
531     if (!process_sp)
532         return byte_order;
533 
534     if (!process_sp->GetByteOrder (byte_order))
535     {
536         // FIXME log here
537     }
538 
539     return byte_order;
540 }
541 
542 size_t
543 NativeRegisterContextLinux_arm64::GetGPRSize() const
544 {
545     return GetRegisterInfoInterface().GetGPRSize();
546 }
547 
548 uint32_t
549 NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
550 {
551     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
552 
553     if (log)
554         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
555 
556     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
557     if (!process_sp)
558         return false;
559 
560     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
561     // Check if our hardware breakpoint and watchpoint information is updated.
562     if (m_refresh_hwdebug_info)
563     {
564         process_p->ReadHardwareDebugInfo (m_thread.GetID (), m_max_hwp_supported,
565                                           m_max_hbp_supported);
566         m_refresh_hwdebug_info = false;
567     }
568 
569     uint32_t control_value, bp_index;
570 
571     // Check if size has a valid hardware breakpoint length.
572     if (size != 4)
573         return LLDB_INVALID_INDEX32;  // Invalid size for a AArch64 hardware breakpoint
574 
575     // Check 4-byte alignment for hardware breakpoint target address.
576     if (addr & 0x03)
577         return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
578 
579     // Setup control value
580     control_value = 0;
581     control_value |= ((1 << size) - 1) << 5;
582     control_value |= (2 << 1) | 1;
583 
584     // Iterate over stored hardware breakpoints
585     // Find a free bp_index or update reference count if duplicate.
586     bp_index = LLDB_INVALID_INDEX32;
587     for (uint32_t i = 0; i < m_max_hbp_supported; i++)
588     {
589         if ((m_hbr_regs[i].control & 1) == 0)
590         {
591             bp_index = i;  // Mark last free slot
592         }
593         else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
594         {
595             bp_index = i;  // Mark duplicate index
596             break;  // Stop searching here
597         }
598     }
599 
600      if (bp_index == LLDB_INVALID_INDEX32)
601         return LLDB_INVALID_INDEX32;
602 
603     // Add new or update existing watchpoint
604     if ((m_hbr_regs[bp_index].control & 1) == 0)
605     {
606         m_hbr_regs[bp_index].address = addr;
607         m_hbr_regs[bp_index].control = control_value;
608         m_hbr_regs[bp_index].refcount = 1;
609 
610         //TODO: PTRACE CALL HERE for an UPDATE
611     }
612     else
613         m_hbr_regs[bp_index].refcount++;
614 
615     return bp_index;
616 }
617 
618 bool
619 NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx)
620 {
621     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
622 
623     if (log)
624         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
625 
626     if (hw_idx >= m_max_hbp_supported)
627         return false;
628 
629     // Update reference count if multiple references.
630     if (m_hbr_regs[hw_idx].refcount > 1)
631     {
632         m_hbr_regs[hw_idx].refcount--;
633         return true;
634     }
635     else if (m_hbr_regs[hw_idx].refcount == 1)
636     {
637         m_hbr_regs[hw_idx].control &= ~1;
638         m_hbr_regs[hw_idx].address = 0;
639         m_hbr_regs[hw_idx].refcount = 0;
640 
641         //TODO: PTRACE CALL HERE for an UPDATE
642         return true;
643     }
644 
645     return false;
646 }
647 
648 uint32_t
649 NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints ()
650 {
651     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
652 
653     if (log)
654         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
655 
656     return m_max_hwp_supported;
657 }
658 
659 uint32_t
660 NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
661 {
662     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
663 
664     if (log)
665         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
666 
667     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
668     if (!process_sp)
669         return false;
670 
671     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
672     // Check if our hardware breakpoint and watchpoint information is updated.
673     if (m_refresh_hwdebug_info)
674     {
675         process_p->ReadHardwareDebugInfo (m_thread.GetID (), m_max_hwp_supported,
676                                           m_max_hbp_supported);
677         m_refresh_hwdebug_info = false;
678     }
679 
680     uint32_t control_value, wp_index;
681 
682 
683     if (watch_flags != 0x1 && watch_flags != 0x2 && watch_flags != 0x3)
684         return 0;//Error ("Invalid read/write bits for watchpoint");
685 
686     // Check if size has a valid hardware watchpoint length.
687     if (size != 1 && size != 2 && size != 4 && size != 8)
688         return 0;//Error ("Invalid size for watchpoint");
689 
690     // Check 8-byte alignment for hardware watchpoint target address.
691     // TODO: Add support for watching un-aligned addresses
692     if (addr & 0x07)
693         return 0;//Error ("LLDB for AArch64 currently supports 8-byte alignment for hardware watchpoint target address.");
694 
695     // Setup control value
696     control_value = watch_flags << 3;
697     control_value |= ((1 << size) - 1) << 5;
698     control_value |= (2 << 1) | 1;
699 
700     // Iterate over stored watchpoints
701     // Find a free wp_index or update reference count if duplicate.
702     wp_index = LLDB_INVALID_INDEX32;
703     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
704     {
705         if ((m_hwp_regs[i].control & 1) == 0)
706         {
707             wp_index = i; // Mark last free slot
708         }
709         else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
710         {
711             wp_index = i; // Mark duplicate index
712             break; // Stop searching here
713         }
714     }
715 
716      if (wp_index == LLDB_INVALID_INDEX32)
717         return LLDB_INVALID_INDEX32;
718 
719     // Add new or update existing watchpoint
720     if ((m_hwp_regs[wp_index].control & 1) == 0)
721     {
722         m_hwp_regs[wp_index].address = addr;
723         m_hwp_regs[wp_index].control = control_value;
724         m_hwp_regs[wp_index].refcount = 1;
725 
726         // PTRACE call to set corresponding watchpoint register.
727         process_p->WriteHardwareDebugRegs(m_thread.GetID (), &addr,
728                                           &control_value, 0, wp_index);
729     }
730     else
731         m_hwp_regs[wp_index].refcount++;
732 
733     return wp_index;
734 }
735 
736 bool
737 NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index)
738 {
739     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
740 
741     if (log)
742         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
743 
744     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
745     if (!process_sp)
746         return false;
747 
748     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
749 
750     if (wp_index >= m_max_hwp_supported)
751         return false;
752 
753     // Update reference count if multiple references.
754     if (m_hwp_regs[wp_index].refcount > 1)
755     {
756         m_hwp_regs[wp_index].refcount--;
757         return true;
758     }
759     else if (m_hwp_regs[wp_index].refcount == 1)
760     {
761         m_hwp_regs[wp_index].control &= ~1;
762         m_hwp_regs[wp_index].address = 0;
763         m_hwp_regs[wp_index].refcount = 0;
764 
765         //TODO: PTRACE CALL HERE for an UPDATE
766         process_p->WriteHardwareDebugRegs(m_thread.GetID (),
767                                           &m_hwp_regs[wp_index].address,
768                                           &m_hwp_regs[wp_index].control,
769                                           0, wp_index);
770         return true;
771     }
772 
773     return false;
774 }
775 
776 Error
777 NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints ()
778 {
779     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
780 
781     if (log)
782         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
783 
784     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
785 
786     Error ml_error;
787     ml_error.SetErrorToErrno();
788     if (!process_sp)
789         return ml_error;
790 
791     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
792 
793     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
794     {
795         if (m_hwp_regs[i].control & 0x01)
796         {
797             m_hwp_regs[i].control &= ~1;
798             m_hwp_regs[i].address = 0;
799             m_hwp_regs[i].refcount = 0;
800 
801             process_p->WriteHardwareDebugRegs(m_thread.GetID (),
802                                           &m_hwp_regs[i].address,
803                                           &m_hwp_regs[i].control,
804                                           0, i);
805         }
806     }
807 
808     return Error();
809 }
810 
811 uint32_t
812 NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index)
813 {
814     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
815 
816     if (log)
817         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
818     switch ((m_hwp_regs[wp_index].control >> 5) & 0xff)
819     {
820         case 0x01:
821             return 1;
822         case 0x03:
823             return 2;
824         case 0x0f:
825             return 4;
826         case 0xff:
827             return 8;
828         default:
829             return 0;
830     }
831 }
832 bool
833 NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index)
834 {
835     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
836 
837     if (log)
838         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
839 
840     if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
841         return true;
842     else
843         return false;
844 }
845 
846 Error
847 NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
848 {
849     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
850 
851     if (log)
852         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
853 
854     uint32_t watch_size;
855     lldb::addr_t watch_addr;
856 
857     for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
858     {
859         watch_size = GetWatchpointSize (wp_index);
860         watch_addr = m_hwp_regs[wp_index].address;
861 
862         if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
863             && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
864         {
865             return Error();
866         }
867     }
868 
869     wp_index = LLDB_INVALID_INDEX32;
870     return Error();
871 }
872 
873 lldb::addr_t
874 NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index)
875 {
876     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
877 
878     if (log)
879         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
880 
881     if (wp_index >= m_max_hwp_supported)
882         return LLDB_INVALID_ADDRESS;
883 
884     if (WatchpointIsEnabled(wp_index))
885         return m_hwp_regs[wp_index].address;
886     else
887         return LLDB_INVALID_ADDRESS;
888 }
889 
890 bool
891 NativeRegisterContextLinux_arm64::HardwareSingleStep (bool enable)
892 {
893     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
894 
895     if (log)
896         log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
897 
898     return false;
899 }
900