1 //===-- NativeRegisterContextLinux_arm.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(__arm__)
11 
12 #include "NativeRegisterContextLinux_arm.h"
13 
14 #include "lldb/Core/DataBufferHeap.h"
15 #include "lldb/Core/Error.h"
16 #include "lldb/Core/Log.h"
17 #include "lldb/Core/RegisterValue.h"
18 
19 #include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
20 
21 #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr))
22 
23 #ifndef PTRACE_GETHBPREGS
24   #define PTRACE_GETHBPREGS 29
25   #define PTRACE_SETHBPREGS 30
26 #endif
27 #if !defined(PTRACE_TYPE_ARG3)
28   #define PTRACE_TYPE_ARG3 void *
29 #endif
30 #if !defined(PTRACE_TYPE_ARG4)
31   #define PTRACE_TYPE_ARG4 void *
32 #endif
33 
34 using namespace lldb;
35 using namespace lldb_private;
36 using namespace lldb_private::process_linux;
37 
38 // arm general purpose registers.
39 static const uint32_t g_gpr_regnums_arm[] =
40 {
41     gpr_r0_arm,
42     gpr_r1_arm,
43     gpr_r2_arm,
44     gpr_r3_arm,
45     gpr_r4_arm,
46     gpr_r5_arm,
47     gpr_r6_arm,
48     gpr_r7_arm,
49     gpr_r8_arm,
50     gpr_r9_arm,
51     gpr_r10_arm,
52     gpr_r11_arm,
53     gpr_r12_arm,
54     gpr_sp_arm,
55     gpr_lr_arm,
56     gpr_pc_arm,
57     gpr_cpsr_arm,
58     LLDB_INVALID_REGNUM // register sets need to end with this flag
59 };
60 static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == k_num_gpr_registers_arm, \
61               "g_gpr_regnums_arm has wrong number of register infos");
62 
63 // arm floating point registers.
64 static const uint32_t g_fpu_regnums_arm[] =
65 {
66     fpu_s0_arm,
67     fpu_s1_arm,
68     fpu_s2_arm,
69     fpu_s3_arm,
70     fpu_s4_arm,
71     fpu_s5_arm,
72     fpu_s6_arm,
73     fpu_s7_arm,
74     fpu_s8_arm,
75     fpu_s9_arm,
76     fpu_s10_arm,
77     fpu_s11_arm,
78     fpu_s12_arm,
79     fpu_s13_arm,
80     fpu_s14_arm,
81     fpu_s15_arm,
82     fpu_s16_arm,
83     fpu_s17_arm,
84     fpu_s18_arm,
85     fpu_s19_arm,
86     fpu_s20_arm,
87     fpu_s21_arm,
88     fpu_s22_arm,
89     fpu_s23_arm,
90     fpu_s24_arm,
91     fpu_s25_arm,
92     fpu_s26_arm,
93     fpu_s27_arm,
94     fpu_s28_arm,
95     fpu_s29_arm,
96     fpu_s30_arm,
97     fpu_s31_arm,
98     fpu_fpscr_arm,
99     LLDB_INVALID_REGNUM // register sets need to end with this flag
100 };
101 static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \
102               "g_fpu_regnums_arm has wrong number of register infos");
103 
104 namespace {
105     // Number of register sets provided by this context.
106     enum
107     {
108         k_num_register_sets = 2
109     };
110 }
111 
112 // Register sets for arm.
113 static const RegisterSet
114 g_reg_sets_arm[k_num_register_sets] =
115 {
116     { "General Purpose Registers",  "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm },
117     { "Floating Point Registers",   "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm }
118 };
119 
120 NativeRegisterContextLinux*
121 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
122                                                                  NativeThreadProtocol &native_thread,
123                                                                  uint32_t concrete_frame_idx)
124 {
125     return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx);
126 }
127 
128 NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm (const ArchSpec& target_arch,
129                                                                 NativeThreadProtocol &native_thread,
130                                                                 uint32_t concrete_frame_idx) :
131     NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm(target_arch))
132 {
133     switch (target_arch.GetMachine())
134     {
135         case llvm::Triple::arm:
136             m_reg_info.num_registers     = k_num_registers_arm;
137             m_reg_info.num_gpr_registers = k_num_gpr_registers_arm;
138             m_reg_info.num_fpr_registers = k_num_fpr_registers_arm;
139             m_reg_info.last_gpr          = k_last_gpr_arm;
140             m_reg_info.first_fpr         = k_first_fpr_arm;
141             m_reg_info.last_fpr          = k_last_fpr_arm;
142             m_reg_info.first_fpr_v       = fpu_s0_arm;
143             m_reg_info.last_fpr_v        = fpu_s31_arm;
144             m_reg_info.gpr_flags         = gpr_cpsr_arm;
145             break;
146         default:
147             assert(false && "Unhandled target architecture.");
148             break;
149     }
150 
151     ::memset(&m_fpr, 0, sizeof (m_fpr));
152     ::memset(&m_gpr_arm, 0, sizeof (m_gpr_arm));
153     ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs));
154 
155     // 16 is just a maximum value, query hardware for actual watchpoint count
156     m_max_hwp_supported = 16;
157     m_max_hbp_supported = 16;
158     m_refresh_hwdebug_info = true;
159 }
160 
161 uint32_t
162 NativeRegisterContextLinux_arm::GetRegisterSetCount () const
163 {
164     return k_num_register_sets;
165 }
166 
167 uint32_t
168 NativeRegisterContextLinux_arm::GetUserRegisterCount() const
169 {
170     uint32_t count = 0;
171     for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
172         count += g_reg_sets_arm[set_index].num_registers;
173     return count;
174 }
175 
176 const RegisterSet *
177 NativeRegisterContextLinux_arm::GetRegisterSet (uint32_t set_index) const
178 {
179     if (set_index < k_num_register_sets)
180         return &g_reg_sets_arm[set_index];
181 
182     return nullptr;
183 }
184 
185 Error
186 NativeRegisterContextLinux_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
187 {
188     Error error;
189 
190     if (!reg_info)
191     {
192         error.SetErrorString ("reg_info NULL");
193         return error;
194     }
195 
196     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
197 
198     if (IsFPR(reg))
199     {
200         error = ReadFPR();
201         if (error.Fail())
202             return error;
203     }
204     else
205     {
206         uint32_t full_reg = reg;
207         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
208 
209         if (is_subreg)
210         {
211             // Read the full aligned 64-bit register.
212             full_reg = reg_info->invalidate_regs[0];
213         }
214 
215         error = ReadRegisterRaw(full_reg, reg_value);
216 
217         if (error.Success ())
218         {
219             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
220             if (is_subreg && (reg_info->byte_offset & 0x1))
221                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
222 
223             // If our return byte size was greater than the return value reg size, then
224             // use the type specified by reg_info rather than the uint64_t default
225             if (reg_value.GetByteSize() > reg_info->byte_size)
226                 reg_value.SetType(reg_info);
227         }
228         return error;
229     }
230 
231     // Get pointer to m_fpr variable and set the data from it.
232     assert (reg_info->byte_offset < sizeof m_fpr);
233     uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
234     switch (reg_info->byte_size)
235     {
236         case 2:
237             reg_value.SetUInt16(*(uint16_t *)src);
238             break;
239         case 4:
240             reg_value.SetUInt32(*(uint32_t *)src);
241             break;
242         case 8:
243             reg_value.SetUInt64(*(uint64_t *)src);
244             break;
245         default:
246             assert(false && "Unhandled data size.");
247             error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
248             break;
249     }
250 
251     return error;
252 }
253 
254 Error
255 NativeRegisterContextLinux_arm::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
256 {
257     if (!reg_info)
258         return Error ("reg_info NULL");
259 
260     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
261     if (reg_index == LLDB_INVALID_REGNUM)
262         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
263 
264     if (IsGPR(reg_index))
265         return WriteRegisterRaw(reg_index, reg_value);
266 
267     if (IsFPR(reg_index))
268     {
269         // Get pointer to m_fpr variable and set the data to it.
270         assert (reg_info->byte_offset < sizeof(m_fpr));
271         uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
272         switch (reg_info->byte_size)
273         {
274             case 2:
275                 *(uint16_t *)dst = reg_value.GetAsUInt16();
276                 break;
277             case 4:
278                 *(uint32_t *)dst = reg_value.GetAsUInt32();
279                 break;
280             case 8:
281                 *(uint64_t *)dst = reg_value.GetAsUInt64();
282                 break;
283             default:
284                 assert(false && "Unhandled data size.");
285                 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
286         }
287 
288         Error error = WriteFPR();
289         if (error.Fail())
290             return error;
291 
292         return Error ();
293     }
294 
295     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
296 }
297 
298 Error
299 NativeRegisterContextLinux_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
300 {
301     Error error;
302 
303     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
304     if (!data_sp)
305         return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, (uint64_t)REG_CONTEXT_SIZE);
306 
307     error = ReadGPR();
308     if (error.Fail())
309         return error;
310 
311     error = ReadFPR();
312     if (error.Fail())
313         return error;
314 
315     uint8_t *dst = data_sp->GetBytes ();
316     if (dst == nullptr)
317     {
318         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", (uint64_t)REG_CONTEXT_SIZE);
319         return error;
320     }
321 
322     ::memcpy (dst, &m_gpr_arm, GetGPRSize());
323     dst += GetGPRSize();
324     ::memcpy (dst, &m_fpr, sizeof(m_fpr));
325 
326     return error;
327 }
328 
329 Error
330 NativeRegisterContextLinux_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
331 {
332     Error error;
333 
334     if (!data_sp)
335     {
336         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
337         return error;
338     }
339 
340     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
341     {
342         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize ());
343         return error;
344     }
345 
346 
347     uint8_t *src = data_sp->GetBytes ();
348     if (src == nullptr)
349     {
350         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
351         return error;
352     }
353     ::memcpy (&m_gpr_arm, src, GetRegisterInfoInterface ().GetGPRSize ());
354 
355     error = WriteGPR();
356     if (error.Fail())
357         return error;
358 
359     src += GetRegisterInfoInterface ().GetGPRSize ();
360     ::memcpy (&m_fpr, src, sizeof(m_fpr));
361 
362     error = WriteFPR();
363     if (error.Fail())
364         return error;
365 
366     return error;
367 }
368 
369 bool
370 NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const
371 {
372     return reg <= m_reg_info.last_gpr;   // GPR's come first.
373 }
374 
375 bool
376 NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const
377 {
378     return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
379 }
380 
381 uint32_t
382 NativeRegisterContextLinux_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
383 {
384     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
385 
386     if (log)
387         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
388 
389     Error error;
390 
391     // Read hardware breakpoint and watchpoint information.
392     error = ReadHardwareDebugInfo ();
393 
394     if (error.Fail())
395         return LLDB_INVALID_INDEX32;
396 
397     uint32_t control_value = 0, bp_index = 0;
398 
399     // Check if size has a valid hardware breakpoint length.
400     // Thumb instructions are 2-bytes but we have no way here to determine
401     // if target address is a thumb or arm instruction.
402     // TODO: Add support for setting thumb mode hardware breakpoints
403     if (size != 4 && size != 2)
404         return LLDB_INVALID_INDEX32;
405 
406     // Setup control value
407     // Make the byte_mask into a valid Byte Address Select mask
408     control_value = 0xfu << 5;
409 
410     // Enable this breakpoint and make it stop in privileged or user mode;
411     control_value |= 7;
412 
413     // Make sure bits 1:0 are clear in our address
414     // This should be different once we support thumb here.
415     addr &= ~((lldb::addr_t)3);
416 
417     // Iterate over stored hardware breakpoints
418     // Find a free bp_index or update reference count if duplicate.
419     bp_index = LLDB_INVALID_INDEX32;
420 
421     for (uint32_t i = 0; i < m_max_hbp_supported; i++)
422     {
423         if ((m_hbr_regs[i].control & 1) == 0)
424         {
425             bp_index = i;  // Mark last free slot
426         }
427         else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value)
428         {
429             bp_index = i;  // Mark duplicate index
430             break;  // Stop searching here
431         }
432     }
433 
434      if (bp_index == LLDB_INVALID_INDEX32)
435          return LLDB_INVALID_INDEX32;
436 
437     // Add new or update existing watchpoint
438     if ((m_hbr_regs[bp_index].control & 1) == 0)
439     {
440         m_hbr_regs[bp_index].address = addr;
441         m_hbr_regs[bp_index].control = control_value;
442         m_hbr_regs[bp_index].refcount = 1;
443 
444         // PTRACE call to set corresponding hardware breakpoint register.
445         error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
446 
447         if (error.Fail())
448             return LLDB_INVALID_INDEX32;
449     }
450     else
451         m_hbr_regs[bp_index].refcount++;
452 
453     return bp_index;
454 }
455 
456 bool
457 NativeRegisterContextLinux_arm::ClearHardwareBreakpoint (uint32_t hw_idx)
458 {
459     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
460 
461     if (log)
462         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
463 
464     Error error;
465 
466     // Read hardware breakpoint and watchpoint information.
467     error = ReadHardwareDebugInfo ();
468 
469     if (error.Fail())
470         return LLDB_INVALID_INDEX32;
471 
472     if (hw_idx >= m_max_hbp_supported)
473         return false;
474 
475     // Update reference count if multiple references.
476     if (m_hbr_regs[hw_idx].refcount > 1)
477     {
478         m_hbr_regs[hw_idx].refcount--;
479         return true;
480     }
481     else if (m_hbr_regs[hw_idx].refcount == 1)
482     {
483         m_hbr_regs[hw_idx].control &= ~1;
484         m_hbr_regs[hw_idx].address = 0;
485         m_hbr_regs[hw_idx].refcount = 0;
486 
487         // PTRACE call to clear corresponding hardware breakpoint register.
488         WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
489 
490         if (error.Fail())
491             return LLDB_INVALID_INDEX32;
492 
493         return true;
494     }
495 
496     return false;
497 }
498 
499 uint32_t
500 NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints ()
501 {
502     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
503 
504     if (log)
505         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
506 
507     Error error;
508 
509     // Read hardware breakpoint and watchpoint information.
510     error = ReadHardwareDebugInfo ();
511 
512     if (error.Fail())
513         return LLDB_INVALID_INDEX32;
514 
515     return m_max_hwp_supported;
516 }
517 
518 uint32_t
519 NativeRegisterContextLinux_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
520 {
521     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
522 
523     if (log)
524         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
525 
526     Error error;
527 
528     // Read hardware breakpoint and watchpoint information.
529     error = ReadHardwareDebugInfo ();
530 
531     if (error.Fail())
532         return LLDB_INVALID_INDEX32;
533 
534     uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
535 
536     // Check if we are setting watchpoint other than read/write/access
537     // Also update watchpoint flag to match Arm write-read bit configuration.
538     switch (watch_flags)
539     {
540         case 1:
541             watch_flags = 2;
542             break;
543         case 2:
544             watch_flags = 1;
545             break;
546         case 3:
547             break;
548         default:
549             return LLDB_INVALID_INDEX32;
550     }
551 
552     // Can't watch zero bytes
553     // Can't watch more than 4 bytes per WVR/WCR pair
554 
555     if (size == 0 || size > 4)
556         return LLDB_INVALID_INDEX32;
557 
558     // We can only watch up to four bytes that follow a 4 byte aligned address
559     // per watchpoint register pair, so make sure we can properly encode this.
560     addr_word_offset = addr % 4;
561     byte_mask = ((1u << size) - 1u) << addr_word_offset;
562 
563     // Check if we need multiple watchpoint register
564     if (byte_mask > 0xfu)
565         return LLDB_INVALID_INDEX32;
566 
567     // Setup control value
568     // Make the byte_mask into a valid Byte Address Select mask
569     control_value = byte_mask << 5;
570 
571     //Turn on appropriate watchpoint flags read or write
572     control_value |= (watch_flags << 3);
573 
574     // Enable this watchpoint and make it stop in privileged or user mode;
575     control_value |= 7;
576 
577     // Make sure bits 1:0 are clear in our address
578     addr &= ~((lldb::addr_t)3);
579 
580     // Iterate over stored watchpoints
581     // Find a free wp_index or update reference count if duplicate.
582     wp_index = LLDB_INVALID_INDEX32;
583     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
584     {
585         if ((m_hwp_regs[i].control & 1) == 0)
586         {
587             wp_index = i; // Mark last free slot
588         }
589         else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value)
590         {
591             wp_index = i; // Mark duplicate index
592             break; // Stop searching here
593         }
594     }
595 
596      if (wp_index == LLDB_INVALID_INDEX32)
597         return LLDB_INVALID_INDEX32;
598 
599     // Add new or update existing watchpoint
600     if ((m_hwp_regs[wp_index].control & 1) == 0)
601     {
602         // Update watchpoint in local cache
603         m_hwp_regs[wp_index].address = addr;
604         m_hwp_regs[wp_index].control = control_value;
605         m_hwp_regs[wp_index].refcount = 1;
606 
607         // PTRACE call to set corresponding watchpoint register.
608         error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
609 
610         if (error.Fail())
611             return LLDB_INVALID_INDEX32;
612     }
613     else
614         m_hwp_regs[wp_index].refcount++;
615 
616     return wp_index;
617 }
618 
619 bool
620 NativeRegisterContextLinux_arm::ClearHardwareWatchpoint (uint32_t wp_index)
621 {
622     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
623 
624     if (log)
625         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
626 
627     Error error;
628 
629     // Read hardware breakpoint and watchpoint information.
630     error = ReadHardwareDebugInfo ();
631 
632     if (error.Fail())
633         return LLDB_INVALID_INDEX32;
634 
635     if (wp_index >= m_max_hwp_supported)
636         return false;
637 
638     // Update reference count if multiple references.
639     if (m_hwp_regs[wp_index].refcount > 1)
640     {
641         m_hwp_regs[wp_index].refcount--;
642         return true;
643     }
644     else if (m_hwp_regs[wp_index].refcount == 1)
645     {
646         // Update watchpoint in local cache
647         m_hwp_regs[wp_index].control &= ~1;
648         m_hwp_regs[wp_index].address = 0;
649         m_hwp_regs[wp_index].refcount = 0;
650 
651         // Ptrace call to update hardware debug registers
652         error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
653 
654         if (error.Fail())
655             return false;
656 
657         return true;
658     }
659 
660     return false;
661 }
662 
663 Error
664 NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints ()
665 {
666     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
667 
668     if (log)
669         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
670 
671     Error error;
672 
673     // Read hardware breakpoint and watchpoint information.
674     error = ReadHardwareDebugInfo ();
675 
676     if (error.Fail())
677         return error;
678 
679     for (uint32_t i = 0; i < m_max_hwp_supported; i++)
680     {
681         if (m_hwp_regs[i].control & 0x01)
682         {
683             // Clear watchpoints in local cache
684             m_hwp_regs[i].control &= ~1;
685             m_hwp_regs[i].address = 0;
686             m_hwp_regs[i].refcount = 0;
687 
688             // Ptrace call to update hardware debug registers
689             error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
690 
691             if (error.Fail())
692                 return error;
693         }
694     }
695 
696     return Error();
697 }
698 
699 uint32_t
700 NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index)
701 {
702     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
703 
704     if (log)
705         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
706 
707     switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f)
708     {
709         case 0x01:
710             return 1;
711         case 0x03:
712             return 2;
713         case 0x07:
714             return 3;
715         case 0x0f:
716             return 4;
717         default:
718             return 0;
719     }
720 }
721 bool
722 NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index)
723 {
724     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
725 
726     if (log)
727         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
728 
729     if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
730         return true;
731     else
732         return false;
733 }
734 
735 Error
736 NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
737 {
738     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
739 
740     if (log)
741         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
742 
743     uint32_t watch_size;
744     lldb::addr_t watch_addr;
745 
746     for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index)
747     {
748         watch_size = GetWatchpointSize (wp_index);
749         watch_addr = m_hwp_regs[wp_index].address;
750 
751         if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index)
752             && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size)
753         {
754             return Error();
755         }
756     }
757 
758     wp_index = LLDB_INVALID_INDEX32;
759     return Error();
760 }
761 
762 lldb::addr_t
763 NativeRegisterContextLinux_arm::GetWatchpointAddress (uint32_t wp_index)
764 {
765     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
766 
767     if (log)
768         log->Printf ("NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
769 
770     if (wp_index >= m_max_hwp_supported)
771         return LLDB_INVALID_ADDRESS;
772 
773     if (WatchpointIsEnabled(wp_index))
774         return m_hwp_regs[wp_index].address;
775     else
776         return LLDB_INVALID_ADDRESS;
777 }
778 
779 Error
780 NativeRegisterContextLinux_arm::ReadHardwareDebugInfo()
781 {
782     Error error;
783 
784     if (!m_refresh_hwdebug_info)
785     {
786         return Error();
787     }
788 
789     unsigned int cap_val;
790 
791     error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), nullptr, &cap_val, sizeof(unsigned int));
792 
793     if (error.Fail())
794         return error;
795 
796     m_max_hwp_supported = (cap_val >> 8) & 0xff;
797     m_max_hbp_supported = cap_val & 0xff;
798     m_refresh_hwdebug_info = false;
799 
800     return error;
801 }
802 
803 Error
804 NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, int hwb_index)
805 {
806     Error error;
807 
808     lldb::addr_t *addr_buf;
809     uint32_t *ctrl_buf;
810 
811     if (hwbType == eDREGTypeWATCH)
812     {
813         addr_buf = &m_hwp_regs[hwb_index].address;
814         ctrl_buf = &m_hwp_regs[hwb_index].control;
815 
816         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
817                 m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 1),
818                 addr_buf, sizeof(unsigned int));
819 
820         if (error.Fail())
821             return error;
822 
823         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
824                 m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 2),
825                 ctrl_buf, sizeof(unsigned int));
826     }
827     else
828     {
829         addr_buf = &m_hwp_regs[hwb_index].address;
830         ctrl_buf = &m_hwp_regs[hwb_index].control;
831 
832         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
833                 m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 1),
834                 addr_buf, sizeof(unsigned int));
835 
836         if (error.Fail())
837             return error;
838 
839         error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
840                 m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 2),
841                 ctrl_buf, sizeof(unsigned int));
842 
843     }
844 
845     return error;
846 }
847 #endif // defined(__arm__)
848