180814287SRaphael Isemann //===-- NativeRegisterContextLinux_arm.cpp --------------------------------===//
23f57216cSOmair Javaid //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63f57216cSOmair Javaid //
73f57216cSOmair Javaid //===----------------------------------------------------------------------===//
83f57216cSOmair Javaid 
9e85e6021STamas Berghammer #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
10068f8a7eSTamas Berghammer 
113f57216cSOmair Javaid #include "NativeRegisterContextLinux_arm.h"
123f57216cSOmair Javaid 
13d37349f3SPavel Labath #include "Plugins/Process/Linux/NativeProcessLinux.h"
14d37349f3SPavel Labath #include "Plugins/Process/Linux/Procfs.h"
15d37349f3SPavel Labath #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
16d37349f3SPavel Labath #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
17666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
186f9e6901SZachary Turner #include "lldb/Utility/Log.h"
19d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h"
2097206d57SZachary Turner #include "lldb/Utility/Status.h"
21068f8a7eSTamas Berghammer 
22e85e6021STamas Berghammer #include <elf.h>
23*ae8a6602SDavid Spickett #include <sys/uio.h>
24e85e6021STamas Berghammer 
253f57216cSOmair Javaid #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr))
263f57216cSOmair Javaid 
27ce26b7a6STamas Berghammer #ifndef PTRACE_GETVFPREGS
28ce26b7a6STamas Berghammer #define PTRACE_GETVFPREGS 27
29ce26b7a6STamas Berghammer #define PTRACE_SETVFPREGS 28
30ce26b7a6STamas Berghammer #endif
312441aecdSOmair Javaid #ifndef PTRACE_GETHBPREGS
322441aecdSOmair Javaid #define PTRACE_GETHBPREGS 29
332441aecdSOmair Javaid #define PTRACE_SETHBPREGS 30
342441aecdSOmair Javaid #endif
352441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG3)
362441aecdSOmair Javaid #define PTRACE_TYPE_ARG3 void *
372441aecdSOmair Javaid #endif
382441aecdSOmair Javaid #if !defined(PTRACE_TYPE_ARG4)
392441aecdSOmair Javaid #define PTRACE_TYPE_ARG4 void *
402441aecdSOmair Javaid #endif
412441aecdSOmair Javaid 
423f57216cSOmair Javaid using namespace lldb;
433f57216cSOmair Javaid using namespace lldb_private;
443f57216cSOmair Javaid using namespace lldb_private::process_linux;
453f57216cSOmair Javaid 
46e85e6021STamas Berghammer #if defined(__arm__)
47e85e6021STamas Berghammer 
48d37349f3SPavel Labath std::unique_ptr<NativeRegisterContextLinux>
CreateHostNativeRegisterContextLinux(const ArchSpec & target_arch,NativeThreadLinux & native_thread)49b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
50d1486e65SPavel Labath     const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
51a8f3ae7cSJonas Devlieghere   return std::make_unique<NativeRegisterContextLinux_arm>(target_arch,
52d37349f3SPavel Labath                                                            native_thread);
53068f8a7eSTamas Berghammer }
54068f8a7eSTamas Berghammer 
55e85e6021STamas Berghammer #endif // defined(__arm__)
56e85e6021STamas Berghammer 
NativeRegisterContextLinux_arm(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)57b9c1b51eSKate Stone NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
58d37349f3SPavel Labath     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
59e1d4fb1eSPavel Labath     : NativeRegisterContextRegisterInfo(native_thread,
60e1d4fb1eSPavel Labath                                         new RegisterInfoPOSIX_arm(target_arch)),
61e1d4fb1eSPavel Labath       NativeRegisterContextLinux(native_thread) {
6276953321SMuhammad Omair Javaid   assert(target_arch.GetMachine() == llvm::Triple::arm);
633f57216cSOmair Javaid 
643f57216cSOmair Javaid   ::memset(&m_fpr, 0, sizeof(m_fpr));
653f57216cSOmair Javaid   ::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm));
662441aecdSOmair Javaid   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
67d5ffbad2SOmair Javaid   ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs));
682441aecdSOmair Javaid 
692441aecdSOmair Javaid   // 16 is just a maximum value, query hardware for actual watchpoint count
702441aecdSOmair Javaid   m_max_hwp_supported = 16;
712441aecdSOmair Javaid   m_max_hbp_supported = 16;
722441aecdSOmair Javaid   m_refresh_hwdebug_info = true;
733f57216cSOmair Javaid }
743f57216cSOmair Javaid 
GetRegisterInfo() const7576953321SMuhammad Omair Javaid RegisterInfoPOSIX_arm &NativeRegisterContextLinux_arm::GetRegisterInfo() const {
7676953321SMuhammad Omair Javaid   return static_cast<RegisterInfoPOSIX_arm &>(*m_register_info_interface_up);
7776953321SMuhammad Omair Javaid }
7876953321SMuhammad Omair Javaid 
GetRegisterSetCount() const79b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount() const {
8076953321SMuhammad Omair Javaid   return GetRegisterInfo().GetRegisterSetCount();
813f57216cSOmair Javaid }
823f57216cSOmair Javaid 
GetUserRegisterCount() const83b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount() const {
841f149204STamas Berghammer   uint32_t count = 0;
8576953321SMuhammad Omair Javaid   for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
8676953321SMuhammad Omair Javaid     count += GetRegisterSet(set_index)->num_registers;
871f149204STamas Berghammer   return count;
881f149204STamas Berghammer }
891f149204STamas Berghammer 
903f57216cSOmair Javaid const RegisterSet *
GetRegisterSet(uint32_t set_index) const91b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index) const {
9276953321SMuhammad Omair Javaid   return GetRegisterInfo().GetRegisterSet(set_index);
933f57216cSOmair Javaid }
943f57216cSOmair Javaid 
9597206d57SZachary Turner Status
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)9697206d57SZachary Turner NativeRegisterContextLinux_arm::ReadRegister(const RegisterInfo *reg_info,
97b9c1b51eSKate Stone                                              RegisterValue &reg_value) {
9897206d57SZachary Turner   Status error;
993f57216cSOmair Javaid 
100b9c1b51eSKate Stone   if (!reg_info) {
1013f57216cSOmair Javaid     error.SetErrorString("reg_info NULL");
1023f57216cSOmair Javaid     return error;
1033f57216cSOmair Javaid   }
1043f57216cSOmair Javaid 
1053f57216cSOmair Javaid   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
1063f57216cSOmair Javaid 
107b9c1b51eSKate Stone   if (IsFPR(reg)) {
108068f8a7eSTamas Berghammer     error = ReadFPR();
109068f8a7eSTamas Berghammer     if (error.Fail())
1103f57216cSOmair Javaid       return error;
111b9c1b51eSKate Stone   } else {
1123f57216cSOmair Javaid     uint32_t full_reg = reg;
113b9c1b51eSKate Stone     bool is_subreg = reg_info->invalidate_regs &&
114b9c1b51eSKate Stone                      (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
1153f57216cSOmair Javaid 
116b9c1b51eSKate Stone     if (is_subreg) {
1173f57216cSOmair Javaid       // Read the full aligned 64-bit register.
1183f57216cSOmair Javaid       full_reg = reg_info->invalidate_regs[0];
1193f57216cSOmair Javaid     }
1203f57216cSOmair Javaid 
1213f57216cSOmair Javaid     error = ReadRegisterRaw(full_reg, reg_value);
1223f57216cSOmair Javaid 
123b9c1b51eSKate Stone     if (error.Success()) {
12405097246SAdrian Prantl       // If our read was not aligned (for ah,bh,ch,dh), shift our returned
12505097246SAdrian Prantl       // value one byte to the right.
1263f57216cSOmair Javaid       if (is_subreg && (reg_info->byte_offset & 0x1))
1273f57216cSOmair Javaid         reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
1283f57216cSOmair Javaid 
129b9c1b51eSKate Stone       // If our return byte size was greater than the return value reg size,
13005097246SAdrian Prantl       // then use the type specified by reg_info rather than the uint64_t
13105097246SAdrian Prantl       // default
1323f57216cSOmair Javaid       if (reg_value.GetByteSize() > reg_info->byte_size)
1333f57216cSOmair Javaid         reg_value.SetType(reg_info);
1343f57216cSOmair Javaid     }
1353f57216cSOmair Javaid     return error;
1363f57216cSOmair Javaid   }
1373f57216cSOmair Javaid 
1383f57216cSOmair Javaid   // Get pointer to m_fpr variable and set the data from it.
139c40e7b17STamas Berghammer   uint32_t fpr_offset = CalculateFprOffset(reg_info);
140c40e7b17STamas Berghammer   assert(fpr_offset < sizeof m_fpr);
141c40e7b17STamas Berghammer   uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
142b9c1b51eSKate Stone   switch (reg_info->byte_size) {
1433f57216cSOmair Javaid   case 2:
1443f57216cSOmair Javaid     reg_value.SetUInt16(*(uint16_t *)src);
1453f57216cSOmair Javaid     break;
1463f57216cSOmair Javaid   case 4:
1473f57216cSOmair Javaid     reg_value.SetUInt32(*(uint32_t *)src);
1483f57216cSOmair Javaid     break;
1493f57216cSOmair Javaid   case 8:
1503f57216cSOmair Javaid     reg_value.SetUInt64(*(uint64_t *)src);
1513f57216cSOmair Javaid     break;
152b4e95a50STamas Berghammer   case 16:
153b4e95a50STamas Berghammer     reg_value.SetBytes(src, 16, GetByteOrder());
154b4e95a50STamas Berghammer     break;
1553f57216cSOmair Javaid   default:
1563f57216cSOmair Javaid     assert(false && "Unhandled data size.");
157b9c1b51eSKate Stone     error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32,
158b9c1b51eSKate Stone                                    reg_info->byte_size);
1593f57216cSOmair Javaid     break;
1603f57216cSOmair Javaid   }
1613f57216cSOmair Javaid 
1623f57216cSOmair Javaid   return error;
1633f57216cSOmair Javaid }
1643f57216cSOmair Javaid 
16597206d57SZachary Turner Status
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)16697206d57SZachary Turner NativeRegisterContextLinux_arm::WriteRegister(const RegisterInfo *reg_info,
16797206d57SZachary Turner                                               const RegisterValue &reg_value) {
1683f57216cSOmair Javaid   if (!reg_info)
16997206d57SZachary Turner     return Status("reg_info NULL");
1703f57216cSOmair Javaid 
1713f57216cSOmair Javaid   const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
1723f57216cSOmair Javaid   if (reg_index == LLDB_INVALID_REGNUM)
17397206d57SZachary Turner     return Status("no lldb regnum for %s", reg_info && reg_info->name
174b9c1b51eSKate Stone                                                ? reg_info->name
175b9c1b51eSKate Stone                                                : "<unknown register>");
1763f57216cSOmair Javaid 
1773f57216cSOmair Javaid   if (IsGPR(reg_index))
1783f57216cSOmair Javaid     return WriteRegisterRaw(reg_index, reg_value);
1793f57216cSOmair Javaid 
180b9c1b51eSKate Stone   if (IsFPR(reg_index)) {
1813f57216cSOmair Javaid     // Get pointer to m_fpr variable and set the data to it.
182c40e7b17STamas Berghammer     uint32_t fpr_offset = CalculateFprOffset(reg_info);
183c40e7b17STamas Berghammer     assert(fpr_offset < sizeof m_fpr);
184c40e7b17STamas Berghammer     uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
185192331b8SMichał Górny     ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
1863f57216cSOmair Javaid 
187192331b8SMichał Górny     return WriteFPR();
1883f57216cSOmair Javaid   }
1893f57216cSOmair Javaid 
19097206d57SZachary Turner   return Status("failed - register wasn't recognized to be a GPR or an FPR, "
191b9c1b51eSKate Stone                 "write strategy unknown");
1923f57216cSOmair Javaid }
1933f57216cSOmair Javaid 
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)19497206d57SZachary Turner Status NativeRegisterContextLinux_arm::ReadAllRegisterValues(
195c2f64601SJonas Devlieghere     lldb::WritableDataBufferSP &data_sp) {
19697206d57SZachary Turner   Status error;
1973f57216cSOmair Javaid 
1983f57216cSOmair Javaid   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
199068f8a7eSTamas Berghammer   error = ReadGPR();
200068f8a7eSTamas Berghammer   if (error.Fail())
2013f57216cSOmair Javaid     return error;
2023f57216cSOmair Javaid 
203068f8a7eSTamas Berghammer   error = ReadFPR();
204068f8a7eSTamas Berghammer   if (error.Fail())
2053f57216cSOmair Javaid     return error;
2063f57216cSOmair Javaid 
2073f57216cSOmair Javaid   uint8_t *dst = data_sp->GetBytes();
2083f57216cSOmair Javaid   ::memcpy(dst, &m_gpr_arm, GetGPRSize());
2093f57216cSOmair Javaid   dst += GetGPRSize();
2103f57216cSOmair Javaid   ::memcpy(dst, &m_fpr, sizeof(m_fpr));
2113f57216cSOmair Javaid 
2123f57216cSOmair Javaid   return error;
2133f57216cSOmair Javaid }
2143f57216cSOmair Javaid 
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)21597206d57SZachary Turner Status NativeRegisterContextLinux_arm::WriteAllRegisterValues(
216b9c1b51eSKate Stone     const lldb::DataBufferSP &data_sp) {
21797206d57SZachary Turner   Status error;
2183f57216cSOmair Javaid 
219b9c1b51eSKate Stone   if (!data_sp) {
220b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
221d7e2e979SMuhammad Omair Javaid         "NativeRegisterContextLinux_arm::%s invalid data_sp provided",
222b9c1b51eSKate Stone         __FUNCTION__);
2233f57216cSOmair Javaid     return error;
2243f57216cSOmair Javaid   }
2253f57216cSOmair Javaid 
226b9c1b51eSKate Stone   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
227b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
228d7e2e979SMuhammad Omair Javaid         "NativeRegisterContextLinux_arm::%s data_sp contained mismatched "
229b9c1b51eSKate Stone         "data size, expected %" PRIu64 ", actual %" PRIu64,
230b9c1b51eSKate Stone         __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize());
2313f57216cSOmair Javaid     return error;
2323f57216cSOmair Javaid   }
2333f57216cSOmair Javaid 
234b7bf5a7aSBenjamin Kramer   const uint8_t *src = data_sp->GetBytes();
235b9c1b51eSKate Stone   if (src == nullptr) {
236d7e2e979SMuhammad Omair Javaid     error.SetErrorStringWithFormat("NativeRegisterContextLinux_arm::%s "
237b9c1b51eSKate Stone                                    "DataBuffer::GetBytes() returned a null "
238b9c1b51eSKate Stone                                    "pointer",
239b9c1b51eSKate Stone                                    __FUNCTION__);
2403f57216cSOmair Javaid     return error;
2413f57216cSOmair Javaid   }
2423f57216cSOmair Javaid   ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize());
2433f57216cSOmair Javaid 
244068f8a7eSTamas Berghammer   error = WriteGPR();
245068f8a7eSTamas Berghammer   if (error.Fail())
2463f57216cSOmair Javaid     return error;
2473f57216cSOmair Javaid 
2483f57216cSOmair Javaid   src += GetRegisterInfoInterface().GetGPRSize();
2493f57216cSOmair Javaid   ::memcpy(&m_fpr, src, sizeof(m_fpr));
2503f57216cSOmair Javaid 
251068f8a7eSTamas Berghammer   error = WriteFPR();
2523f57216cSOmair Javaid   if (error.Fail())
2533f57216cSOmair Javaid     return error;
2543f57216cSOmair Javaid 
2553f57216cSOmair Javaid   return error;
2563f57216cSOmair Javaid }
2573f57216cSOmair Javaid 
IsGPR(unsigned reg) const258b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const {
25976953321SMuhammad Omair Javaid   if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
26076953321SMuhammad Omair Javaid       RegisterInfoPOSIX_arm::GPRegSet)
26176953321SMuhammad Omair Javaid     return true;
26276953321SMuhammad Omair Javaid   return false;
2633f57216cSOmair Javaid }
2643f57216cSOmair Javaid 
IsFPR(unsigned reg) const265b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const {
26676953321SMuhammad Omair Javaid   if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
26776953321SMuhammad Omair Javaid       RegisterInfoPOSIX_arm::FPRegSet)
26876953321SMuhammad Omair Javaid     return true;
26976953321SMuhammad Omair Javaid   return false;
2703f57216cSOmair Javaid }
2713f57216cSOmair Javaid 
NumSupportedHardwareBreakpoints()272d5ffbad2SOmair Javaid uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
2734fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Breakpoints);
274d5ffbad2SOmair Javaid 
27563e5fb76SJonas Devlieghere   LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
276d5ffbad2SOmair Javaid 
27797206d57SZachary Turner   Status error;
278d5ffbad2SOmair Javaid 
279d5ffbad2SOmair Javaid   // Read hardware breakpoint and watchpoint information.
280d5ffbad2SOmair Javaid   error = ReadHardwareDebugInfo();
281d5ffbad2SOmair Javaid 
282d5ffbad2SOmair Javaid   if (error.Fail())
283d5ffbad2SOmair Javaid     return 0;
284d5ffbad2SOmair Javaid 
285d5ffbad2SOmair Javaid   LLDB_LOG(log, "{0}", m_max_hbp_supported);
286d5ffbad2SOmair Javaid   return m_max_hbp_supported;
287d5ffbad2SOmair Javaid }
288d5ffbad2SOmair Javaid 
2892441aecdSOmair Javaid uint32_t
SetHardwareBreakpoint(lldb::addr_t addr,size_t size)290b9c1b51eSKate Stone NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
291b9c1b51eSKate Stone                                                       size_t size) {
2924fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Breakpoints);
293ea1b6b17SPavel Labath   LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
2942441aecdSOmair Javaid 
2952441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
29697206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
2972441aecdSOmair Javaid 
2982441aecdSOmair Javaid   if (error.Fail())
2992441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
3002441aecdSOmair Javaid 
3012441aecdSOmair Javaid   uint32_t control_value = 0, bp_index = 0;
3022441aecdSOmair Javaid 
303d5ffbad2SOmair Javaid   // Setup address and control values.
304d5ffbad2SOmair Javaid   // Use size to get a hint of arm vs thumb modes.
305d5ffbad2SOmair Javaid   switch (size) {
306d5ffbad2SOmair Javaid   case 2:
307d5ffbad2SOmair Javaid     control_value = (0x3 << 5) | 7;
308d5ffbad2SOmair Javaid     addr &= ~1;
309d5ffbad2SOmair Javaid     break;
310d5ffbad2SOmair Javaid   case 4:
311d5ffbad2SOmair Javaid     control_value = (0xfu << 5) | 7;
312d5ffbad2SOmair Javaid     addr &= ~3;
313d5ffbad2SOmair Javaid     break;
314d5ffbad2SOmair Javaid   default:
3152441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
316d5ffbad2SOmair Javaid   }
3172441aecdSOmair Javaid 
318d5ffbad2SOmair Javaid   // Iterate over stored breakpoints and find a free bp_index
3192441aecdSOmair Javaid   bp_index = LLDB_INVALID_INDEX32;
320b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
321b9c1b51eSKate Stone     if ((m_hbr_regs[i].control & 1) == 0) {
3222441aecdSOmair Javaid       bp_index = i; // Mark last free slot
323d5ffbad2SOmair Javaid     } else if (m_hbr_regs[i].address == addr) {
324d5ffbad2SOmair Javaid       return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
3252441aecdSOmair Javaid     }
3262441aecdSOmair Javaid   }
3272441aecdSOmair Javaid 
3282441aecdSOmair Javaid   if (bp_index == LLDB_INVALID_INDEX32)
3292441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
3302441aecdSOmair Javaid 
331d5ffbad2SOmair Javaid   // Update breakpoint in local cache
332d5ffbad2SOmair Javaid   m_hbr_regs[bp_index].real_addr = addr;
3332441aecdSOmair Javaid   m_hbr_regs[bp_index].address = addr;
3342441aecdSOmair Javaid   m_hbr_regs[bp_index].control = control_value;
3352441aecdSOmair Javaid 
3362441aecdSOmair Javaid   // PTRACE call to set corresponding hardware breakpoint register.
3372441aecdSOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
3382441aecdSOmair Javaid 
339b9c1b51eSKate Stone   if (error.Fail()) {
340d5510d1eSOmair Javaid     m_hbr_regs[bp_index].address = 0;
341d5510d1eSOmair Javaid     m_hbr_regs[bp_index].control &= ~1;
342d5510d1eSOmair Javaid 
3432441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
3442441aecdSOmair Javaid   }
3452441aecdSOmair Javaid 
3462441aecdSOmair Javaid   return bp_index;
3472441aecdSOmair Javaid }
3482441aecdSOmair Javaid 
ClearHardwareBreakpoint(uint32_t hw_idx)349b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
3504fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Breakpoints);
351ea1b6b17SPavel Labath   LLDB_LOG(log, "hw_idx: {0}", hw_idx);
3522441aecdSOmair Javaid 
3532441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
35497206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
3552441aecdSOmair Javaid 
3562441aecdSOmair Javaid   if (error.Fail())
3574aa984c1SOmair Javaid     return false;
3582441aecdSOmair Javaid 
3592441aecdSOmair Javaid   if (hw_idx >= m_max_hbp_supported)
3602441aecdSOmair Javaid     return false;
3612441aecdSOmair Javaid 
362d5510d1eSOmair Javaid   // Create a backup we can revert to in case of failure.
363d5510d1eSOmair Javaid   lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
364d5510d1eSOmair Javaid   uint32_t tempControl = m_hbr_regs[hw_idx].control;
365d5510d1eSOmair Javaid 
3662441aecdSOmair Javaid   m_hbr_regs[hw_idx].control &= ~1;
3672441aecdSOmair Javaid   m_hbr_regs[hw_idx].address = 0;
3682441aecdSOmair Javaid 
3692441aecdSOmair Javaid   // PTRACE call to clear corresponding hardware breakpoint register.
370d5ffbad2SOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
3712441aecdSOmair Javaid 
372b9c1b51eSKate Stone   if (error.Fail()) {
373d5510d1eSOmair Javaid     m_hbr_regs[hw_idx].control = tempControl;
374d5510d1eSOmair Javaid     m_hbr_regs[hw_idx].address = tempAddr;
375d5510d1eSOmair Javaid 
3764aa984c1SOmair Javaid     return false;
377d5510d1eSOmair Javaid   }
3782441aecdSOmair Javaid 
3792441aecdSOmair Javaid   return true;
3802441aecdSOmair Javaid }
3812441aecdSOmair Javaid 
GetHardwareBreakHitIndex(uint32_t & bp_index,lldb::addr_t trap_addr)38297206d57SZachary Turner Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
383d5ffbad2SOmair Javaid     uint32_t &bp_index, lldb::addr_t trap_addr) {
3844fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Breakpoints);
385d5ffbad2SOmair Javaid 
386d7e2e979SMuhammad Omair Javaid   LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
387d5ffbad2SOmair Javaid 
388d5ffbad2SOmair Javaid   lldb::addr_t break_addr;
389d5ffbad2SOmair Javaid 
390d5ffbad2SOmair Javaid   for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
391d5ffbad2SOmair Javaid     break_addr = m_hbr_regs[bp_index].address;
392d5ffbad2SOmair Javaid 
393d5ffbad2SOmair Javaid     if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
394d5ffbad2SOmair Javaid       m_hbr_regs[bp_index].hit_addr = trap_addr;
39597206d57SZachary Turner       return Status();
396d5ffbad2SOmair Javaid     }
397d5ffbad2SOmair Javaid   }
398d5ffbad2SOmair Javaid 
399d5ffbad2SOmair Javaid   bp_index = LLDB_INVALID_INDEX32;
40097206d57SZachary Turner   return Status();
401d5ffbad2SOmair Javaid }
402d5ffbad2SOmair Javaid 
ClearAllHardwareBreakpoints()40397206d57SZachary Turner Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
4044fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Breakpoints);
405d5ffbad2SOmair Javaid 
40663e5fb76SJonas Devlieghere   LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
407d5ffbad2SOmair Javaid 
40897206d57SZachary Turner   Status error;
409d5ffbad2SOmair Javaid 
410d5ffbad2SOmair Javaid   // Read hardware breakpoint and watchpoint information.
411d5ffbad2SOmair Javaid   error = ReadHardwareDebugInfo();
412d5ffbad2SOmair Javaid 
413d5ffbad2SOmair Javaid   if (error.Fail())
414d5ffbad2SOmair Javaid     return error;
415d5ffbad2SOmair Javaid 
416d5ffbad2SOmair Javaid   lldb::addr_t tempAddr = 0;
417d5ffbad2SOmair Javaid   uint32_t tempControl = 0;
418d5ffbad2SOmair Javaid 
419d5ffbad2SOmair Javaid   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
420d5ffbad2SOmair Javaid     if (m_hbr_regs[i].control & 0x01) {
421d5ffbad2SOmair Javaid       // Create a backup we can revert to in case of failure.
422d5ffbad2SOmair Javaid       tempAddr = m_hbr_regs[i].address;
423d5ffbad2SOmair Javaid       tempControl = m_hbr_regs[i].control;
424d5ffbad2SOmair Javaid 
425d5ffbad2SOmair Javaid       // Clear breakpoints in local cache
426d5ffbad2SOmair Javaid       m_hbr_regs[i].control &= ~1;
427d5ffbad2SOmair Javaid       m_hbr_regs[i].address = 0;
428d5ffbad2SOmair Javaid 
429d5ffbad2SOmair Javaid       // Ptrace call to update hardware debug registers
430d5ffbad2SOmair Javaid       error = WriteHardwareDebugRegs(eDREGTypeBREAK, i);
431d5ffbad2SOmair Javaid 
432d5ffbad2SOmair Javaid       if (error.Fail()) {
433d5ffbad2SOmair Javaid         m_hbr_regs[i].control = tempControl;
434d5ffbad2SOmair Javaid         m_hbr_regs[i].address = tempAddr;
435d5ffbad2SOmair Javaid 
436d5ffbad2SOmair Javaid         return error;
437d5ffbad2SOmair Javaid       }
438d5ffbad2SOmair Javaid     }
439d5ffbad2SOmair Javaid   }
440d5ffbad2SOmair Javaid 
44197206d57SZachary Turner   return Status();
4422441aecdSOmair Javaid }
4432441aecdSOmair Javaid 
NumSupportedHardwareWatchpoints()444b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
4454fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Watchpoints);
4462441aecdSOmair Javaid 
4472441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
44897206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
4492441aecdSOmair Javaid 
4502441aecdSOmair Javaid   if (error.Fail())
45162661473SOmair Javaid     return 0;
4522441aecdSOmair Javaid 
453ea1b6b17SPavel Labath   LLDB_LOG(log, "{0}", m_max_hwp_supported);
4542441aecdSOmair Javaid   return m_max_hwp_supported;
4552441aecdSOmair Javaid }
4562441aecdSOmair Javaid 
SetHardwareWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags)457b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
458b9c1b51eSKate Stone     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
4594fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Watchpoints);
460ea1b6b17SPavel Labath   LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
461ea1b6b17SPavel Labath            watch_flags);
4622441aecdSOmair Javaid 
4632441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
46497206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
4652441aecdSOmair Javaid 
4662441aecdSOmair Javaid   if (error.Fail())
4672441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
4682441aecdSOmair Javaid 
4692441aecdSOmair Javaid   uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
470c6dc90efSOmair Javaid   lldb::addr_t real_addr = addr;
4712441aecdSOmair Javaid 
47205097246SAdrian Prantl   // Check if we are setting watchpoint other than read/write/access Also
47305097246SAdrian Prantl   // update watchpoint flag to match Arm write-read bit configuration.
474b9c1b51eSKate Stone   switch (watch_flags) {
4752441aecdSOmair Javaid   case 1:
4762441aecdSOmair Javaid     watch_flags = 2;
4772441aecdSOmair Javaid     break;
4782441aecdSOmair Javaid   case 2:
4792441aecdSOmair Javaid     watch_flags = 1;
4802441aecdSOmair Javaid     break;
4812441aecdSOmair Javaid   case 3:
4822441aecdSOmair Javaid     break;
4832441aecdSOmair Javaid   default:
4842441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
4852441aecdSOmair Javaid   }
4862441aecdSOmair Javaid 
4872441aecdSOmair Javaid   // Can't watch zero bytes
4882441aecdSOmair Javaid   // Can't watch more than 4 bytes per WVR/WCR pair
4892441aecdSOmair Javaid 
4902441aecdSOmair Javaid   if (size == 0 || size > 4)
4912441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
4922441aecdSOmair Javaid 
49305097246SAdrian Prantl   // Check 4-byte alignment for hardware watchpoint target address. Below is a
49405097246SAdrian Prantl   // hack to recalculate address and size in order to make sure we can watch
495e9264b74SKazuaki Ishizaki   // non 4-byte aligned addresses as well.
496b9c1b51eSKate Stone   if (addr & 0x03) {
497c6dc90efSOmair Javaid     uint8_t watch_mask = (addr & 0x03) + size;
498c6dc90efSOmair Javaid 
499c6dc90efSOmair Javaid     if (watch_mask > 0x04)
500c6dc90efSOmair Javaid       return LLDB_INVALID_INDEX32;
501c6dc90efSOmair Javaid     else if (watch_mask <= 0x02)
502c6dc90efSOmair Javaid       size = 2;
503c6dc90efSOmair Javaid     else if (watch_mask <= 0x04)
504c6dc90efSOmair Javaid       size = 4;
505c6dc90efSOmair Javaid 
506c6dc90efSOmair Javaid     addr = addr & (~0x03);
507c6dc90efSOmair Javaid   }
508c6dc90efSOmair Javaid 
5092441aecdSOmair Javaid   // We can only watch up to four bytes that follow a 4 byte aligned address
5102441aecdSOmair Javaid   // per watchpoint register pair, so make sure we can properly encode this.
5112441aecdSOmair Javaid   addr_word_offset = addr % 4;
5122441aecdSOmair Javaid   byte_mask = ((1u << size) - 1u) << addr_word_offset;
5132441aecdSOmair Javaid 
5142441aecdSOmair Javaid   // Check if we need multiple watchpoint register
5152441aecdSOmair Javaid   if (byte_mask > 0xfu)
5162441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5172441aecdSOmair Javaid 
5182441aecdSOmair Javaid   // Setup control value
5192441aecdSOmair Javaid   // Make the byte_mask into a valid Byte Address Select mask
5202441aecdSOmair Javaid   control_value = byte_mask << 5;
5212441aecdSOmair Javaid 
5222441aecdSOmair Javaid   // Turn on appropriate watchpoint flags read or write
5232441aecdSOmair Javaid   control_value |= (watch_flags << 3);
5242441aecdSOmair Javaid 
5252441aecdSOmair Javaid   // Enable this watchpoint and make it stop in privileged or user mode;
5262441aecdSOmair Javaid   control_value |= 7;
5272441aecdSOmair Javaid 
5282441aecdSOmair Javaid   // Make sure bits 1:0 are clear in our address
5292441aecdSOmair Javaid   addr &= ~((lldb::addr_t)3);
5302441aecdSOmair Javaid 
53105ac4c44SOmair Javaid   // Iterate over stored watchpoints and find a free wp_index
5322441aecdSOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
533b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
534b9c1b51eSKate Stone     if ((m_hwp_regs[i].control & 1) == 0) {
5352441aecdSOmair Javaid       wp_index = i; // Mark last free slot
53605ac4c44SOmair Javaid     } else if (m_hwp_regs[i].address == addr) {
53705ac4c44SOmair Javaid       return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
5382441aecdSOmair Javaid     }
5392441aecdSOmair Javaid   }
5402441aecdSOmair Javaid 
5412441aecdSOmair Javaid   if (wp_index == LLDB_INVALID_INDEX32)
5422441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5432441aecdSOmair Javaid 
5442441aecdSOmair Javaid   // Update watchpoint in local cache
545c6dc90efSOmair Javaid   m_hwp_regs[wp_index].real_addr = real_addr;
5462441aecdSOmair Javaid   m_hwp_regs[wp_index].address = addr;
5472441aecdSOmair Javaid   m_hwp_regs[wp_index].control = control_value;
5482441aecdSOmair Javaid 
5492441aecdSOmair Javaid   // PTRACE call to set corresponding watchpoint register.
5502441aecdSOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
5512441aecdSOmair Javaid 
552b9c1b51eSKate Stone   if (error.Fail()) {
553d5510d1eSOmair Javaid     m_hwp_regs[wp_index].address = 0;
554d5510d1eSOmair Javaid     m_hwp_regs[wp_index].control &= ~1;
555d5510d1eSOmair Javaid 
5562441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5572441aecdSOmair Javaid   }
5582441aecdSOmair Javaid 
5592441aecdSOmair Javaid   return wp_index;
5602441aecdSOmair Javaid }
5612441aecdSOmair Javaid 
ClearHardwareWatchpoint(uint32_t wp_index)562b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
563b9c1b51eSKate Stone     uint32_t wp_index) {
5644fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Watchpoints);
565ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
5662441aecdSOmair Javaid 
5672441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
56897206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
5692441aecdSOmair Javaid 
5702441aecdSOmair Javaid   if (error.Fail())
5714aa984c1SOmair Javaid     return false;
5722441aecdSOmair Javaid 
5732441aecdSOmair Javaid   if (wp_index >= m_max_hwp_supported)
5742441aecdSOmair Javaid     return false;
5752441aecdSOmair Javaid 
576d5510d1eSOmair Javaid   // Create a backup we can revert to in case of failure.
577d5510d1eSOmair Javaid   lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
578d5510d1eSOmair Javaid   uint32_t tempControl = m_hwp_regs[wp_index].control;
579d5510d1eSOmair Javaid 
5802441aecdSOmair Javaid   // Update watchpoint in local cache
5812441aecdSOmair Javaid   m_hwp_regs[wp_index].control &= ~1;
5822441aecdSOmair Javaid   m_hwp_regs[wp_index].address = 0;
5832441aecdSOmair Javaid 
5842441aecdSOmair Javaid   // Ptrace call to update hardware debug registers
5852441aecdSOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
5862441aecdSOmair Javaid 
587b9c1b51eSKate Stone   if (error.Fail()) {
588d5510d1eSOmair Javaid     m_hwp_regs[wp_index].control = tempControl;
589d5510d1eSOmair Javaid     m_hwp_regs[wp_index].address = tempAddr;
590d5510d1eSOmair Javaid 
5912441aecdSOmair Javaid     return false;
592d5510d1eSOmair Javaid   }
5932441aecdSOmair Javaid 
5942441aecdSOmair Javaid   return true;
5952441aecdSOmair Javaid }
5962441aecdSOmair Javaid 
ClearAllHardwareWatchpoints()59797206d57SZachary Turner Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
5982441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
59997206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
6002441aecdSOmair Javaid 
6012441aecdSOmair Javaid   if (error.Fail())
6022441aecdSOmair Javaid     return error;
6032441aecdSOmair Javaid 
604d5510d1eSOmair Javaid   lldb::addr_t tempAddr = 0;
60505ac4c44SOmair Javaid   uint32_t tempControl = 0;
606d5510d1eSOmair Javaid 
607b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
608b9c1b51eSKate Stone     if (m_hwp_regs[i].control & 0x01) {
609d5510d1eSOmair Javaid       // Create a backup we can revert to in case of failure.
610d5510d1eSOmair Javaid       tempAddr = m_hwp_regs[i].address;
611d5510d1eSOmair Javaid       tempControl = m_hwp_regs[i].control;
612d5510d1eSOmair Javaid 
6132441aecdSOmair Javaid       // Clear watchpoints in local cache
6142441aecdSOmair Javaid       m_hwp_regs[i].control &= ~1;
6152441aecdSOmair Javaid       m_hwp_regs[i].address = 0;
6162441aecdSOmair Javaid 
6172441aecdSOmair Javaid       // Ptrace call to update hardware debug registers
6182441aecdSOmair Javaid       error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
6192441aecdSOmair Javaid 
620b9c1b51eSKate Stone       if (error.Fail()) {
621d5510d1eSOmair Javaid         m_hwp_regs[i].control = tempControl;
622d5510d1eSOmair Javaid         m_hwp_regs[i].address = tempAddr;
623d5510d1eSOmair Javaid 
6242441aecdSOmair Javaid         return error;
6252441aecdSOmair Javaid       }
6262441aecdSOmair Javaid     }
627d5510d1eSOmair Javaid   }
6282441aecdSOmair Javaid 
62997206d57SZachary Turner   return Status();
6302441aecdSOmair Javaid }
6312441aecdSOmair Javaid 
GetWatchpointSize(uint32_t wp_index)632b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) {
6334fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Watchpoints);
634ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
6352441aecdSOmair Javaid 
636b9c1b51eSKate Stone   switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
6372441aecdSOmair Javaid   case 0x01:
6382441aecdSOmair Javaid     return 1;
6392441aecdSOmair Javaid   case 0x03:
6402441aecdSOmair Javaid     return 2;
6412441aecdSOmair Javaid   case 0x07:
6422441aecdSOmair Javaid     return 3;
6432441aecdSOmair Javaid   case 0x0f:
6442441aecdSOmair Javaid     return 4;
6452441aecdSOmair Javaid   default:
6462441aecdSOmair Javaid     return 0;
6472441aecdSOmair Javaid   }
6482441aecdSOmair Javaid }
WatchpointIsEnabled(uint32_t wp_index)649b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) {
6504fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Watchpoints);
651ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
6522441aecdSOmair Javaid 
6532441aecdSOmair Javaid   if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
6542441aecdSOmair Javaid     return true;
6552441aecdSOmair Javaid   else
6562441aecdSOmair Javaid     return false;
6572441aecdSOmair Javaid }
6582441aecdSOmair Javaid 
65997206d57SZachary Turner Status
GetWatchpointHitIndex(uint32_t & wp_index,lldb::addr_t trap_addr)66097206d57SZachary Turner NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index,
66197206d57SZachary Turner                                                       lldb::addr_t trap_addr) {
6624fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Watchpoints);
663ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
6642441aecdSOmair Javaid 
6652441aecdSOmair Javaid   uint32_t watch_size;
6662441aecdSOmair Javaid   lldb::addr_t watch_addr;
6672441aecdSOmair Javaid 
668b9c1b51eSKate Stone   for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
6692441aecdSOmair Javaid     watch_size = GetWatchpointSize(wp_index);
6702441aecdSOmair Javaid     watch_addr = m_hwp_regs[wp_index].address;
6712441aecdSOmair Javaid 
67205ac4c44SOmair Javaid     if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
67305ac4c44SOmair Javaid         trap_addr < watch_addr + watch_size) {
674c6dc90efSOmair Javaid       m_hwp_regs[wp_index].hit_addr = trap_addr;
67597206d57SZachary Turner       return Status();
6762441aecdSOmair Javaid     }
6772441aecdSOmair Javaid   }
6782441aecdSOmair Javaid 
6792441aecdSOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
68097206d57SZachary Turner   return Status();
6812441aecdSOmair Javaid }
6822441aecdSOmair Javaid 
6832441aecdSOmair Javaid lldb::addr_t
GetWatchpointAddress(uint32_t wp_index)684b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) {
6854fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Watchpoints);
686ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
6872441aecdSOmair Javaid 
6882441aecdSOmair Javaid   if (wp_index >= m_max_hwp_supported)
6892441aecdSOmair Javaid     return LLDB_INVALID_ADDRESS;
6902441aecdSOmair Javaid 
6912441aecdSOmair Javaid   if (WatchpointIsEnabled(wp_index))
692c6dc90efSOmair Javaid     return m_hwp_regs[wp_index].real_addr;
693c6dc90efSOmair Javaid   else
694c6dc90efSOmair Javaid     return LLDB_INVALID_ADDRESS;
695c6dc90efSOmair Javaid }
696c6dc90efSOmair Javaid 
697c6dc90efSOmair Javaid lldb::addr_t
GetWatchpointHitAddress(uint32_t wp_index)698b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) {
6994fa1ad05SPavel Labath   Log *log = GetLog(POSIXLog::Watchpoints);
700ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
701c6dc90efSOmair Javaid 
702c6dc90efSOmair Javaid   if (wp_index >= m_max_hwp_supported)
703c6dc90efSOmair Javaid     return LLDB_INVALID_ADDRESS;
704c6dc90efSOmair Javaid 
705c6dc90efSOmair Javaid   if (WatchpointIsEnabled(wp_index))
706c6dc90efSOmair Javaid     return m_hwp_regs[wp_index].hit_addr;
7072441aecdSOmair Javaid   else
7082441aecdSOmair Javaid     return LLDB_INVALID_ADDRESS;
7092441aecdSOmair Javaid }
7102441aecdSOmair Javaid 
ReadHardwareDebugInfo()71197206d57SZachary Turner Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
71297206d57SZachary Turner   Status error;
7132441aecdSOmair Javaid 
714b9c1b51eSKate Stone   if (!m_refresh_hwdebug_info) {
71597206d57SZachary Turner     return Status();
7162441aecdSOmair Javaid   }
7172441aecdSOmair Javaid 
7182441aecdSOmair Javaid   unsigned int cap_val;
7192441aecdSOmair Javaid 
720b9c1b51eSKate Stone   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(),
721b9c1b51eSKate Stone                                             nullptr, &cap_val,
722b9c1b51eSKate Stone                                             sizeof(unsigned int));
7232441aecdSOmair Javaid 
7242441aecdSOmair Javaid   if (error.Fail())
7252441aecdSOmair Javaid     return error;
7262441aecdSOmair Javaid 
7272441aecdSOmair Javaid   m_max_hwp_supported = (cap_val >> 8) & 0xff;
7282441aecdSOmair Javaid   m_max_hbp_supported = cap_val & 0xff;
7292441aecdSOmair Javaid   m_refresh_hwdebug_info = false;
7302441aecdSOmair Javaid 
7312441aecdSOmair Javaid   return error;
7322441aecdSOmair Javaid }
7332441aecdSOmair Javaid 
WriteHardwareDebugRegs(int hwbType,int hwb_index)73497206d57SZachary Turner Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType,
735b9c1b51eSKate Stone                                                               int hwb_index) {
73697206d57SZachary Turner   Status error;
7372441aecdSOmair Javaid 
7382441aecdSOmair Javaid   lldb::addr_t *addr_buf;
7392441aecdSOmair Javaid   uint32_t *ctrl_buf;
7402441aecdSOmair Javaid 
741b9c1b51eSKate Stone   if (hwbType == eDREGTypeWATCH) {
7422441aecdSOmair Javaid     addr_buf = &m_hwp_regs[hwb_index].address;
7432441aecdSOmair Javaid     ctrl_buf = &m_hwp_regs[hwb_index].control;
7442441aecdSOmair Javaid 
745b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
746b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
747b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf,
748b9c1b51eSKate Stone         sizeof(unsigned int));
7492441aecdSOmair Javaid 
7502441aecdSOmair Javaid     if (error.Fail())
7512441aecdSOmair Javaid       return error;
7522441aecdSOmair Javaid 
753b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
754b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
755b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
756b9c1b51eSKate Stone         sizeof(unsigned int));
757b9c1b51eSKate Stone   } else {
758d5ffbad2SOmair Javaid     addr_buf = &m_hbr_regs[hwb_index].address;
759d5ffbad2SOmair Javaid     ctrl_buf = &m_hbr_regs[hwb_index].control;
7602441aecdSOmair Javaid 
761b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
762b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
763b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf,
764b9c1b51eSKate Stone         sizeof(unsigned int));
7652441aecdSOmair Javaid 
7662441aecdSOmair Javaid     if (error.Fail())
7672441aecdSOmair Javaid       return error;
7682441aecdSOmair Javaid 
769b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
770b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
771b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
772b9c1b51eSKate Stone         sizeof(unsigned int));
7732441aecdSOmair Javaid   }
7742441aecdSOmair Javaid 
7752441aecdSOmair Javaid   return error;
7762441aecdSOmair Javaid }
777c40e7b17STamas Berghammer 
CalculateFprOffset(const RegisterInfo * reg_info) const778b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
779b9c1b51eSKate Stone     const RegisterInfo *reg_info) const {
78076953321SMuhammad Omair Javaid   return reg_info->byte_offset - GetGPRSize();
781c40e7b17STamas Berghammer }
782c40e7b17STamas Berghammer 
DoReadRegisterValue(uint32_t offset,const char * reg_name,uint32_t size,RegisterValue & value)78397206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoReadRegisterValue(
784b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, uint32_t size,
785b9c1b51eSKate Stone     RegisterValue &value) {
786b9c1b51eSKate Stone   // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android
78705097246SAdrian Prantl   // devices (always return "Bad address"). To avoid using PTRACE_PEEKUSER we
78805097246SAdrian Prantl   // read out the full GPR register set instead. This approach is about 4 times
789e9264b74SKazuaki Ishizaki   // slower but the performance overhead is negligible in comparison to
79005097246SAdrian Prantl   // processing time in lldb-server.
791e85e6021STamas Berghammer   assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
792e85e6021STamas Berghammer   if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
79397206d57SZachary Turner     return Status("Register isn't fit into the size of the GPR area");
794e85e6021STamas Berghammer 
7953f3673eaSPavel Labath   Status error = ReadGPR();
796e85e6021STamas Berghammer   if (error.Fail())
797e85e6021STamas Berghammer     return error;
798e85e6021STamas Berghammer 
799e85e6021STamas Berghammer   value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]);
80097206d57SZachary Turner   return Status();
801e85e6021STamas Berghammer }
802e85e6021STamas Berghammer 
DoWriteRegisterValue(uint32_t offset,const char * reg_name,const RegisterValue & value)80397206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoWriteRegisterValue(
804b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, const RegisterValue &value) {
805b9c1b51eSKate Stone   // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android
80605097246SAdrian Prantl   // devices (always return "Bad address"). To avoid using PTRACE_POKEUSER we
80705097246SAdrian Prantl   // read out the full GPR register set, modify the requested register and
80805097246SAdrian Prantl   // write it back. This approach is about 4 times slower but the performance
809e9264b74SKazuaki Ishizaki   // overhead is negligible in comparison to processing time in lldb-server.
810ce26b7a6STamas Berghammer   assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
811ce26b7a6STamas Berghammer   if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
81297206d57SZachary Turner     return Status("Register isn't fit into the size of the GPR area");
813ce26b7a6STamas Berghammer 
8143f3673eaSPavel Labath   Status error = ReadGPR();
815ce26b7a6STamas Berghammer   if (error.Fail())
816ce26b7a6STamas Berghammer     return error;
817ce26b7a6STamas Berghammer 
818a7d7f7cfSOmair Javaid   uint32_t reg_value = value.GetAsUInt32();
819a7d7f7cfSOmair Javaid   // As precaution for an undefined behavior encountered while setting PC we
820a7d7f7cfSOmair Javaid   // will clear thumb bit of new PC if we are already in thumb mode; that is
821a7d7f7cfSOmair Javaid   // CPSR thumb mode bit is set.
822b9c1b51eSKate Stone   if (offset / sizeof(uint32_t) == gpr_pc_arm) {
82305097246SAdrian Prantl     // Check if we are already in thumb mode and thumb bit of current PC is
82405097246SAdrian Prantl     // read out to be zero and thumb bit of next PC is read out to be one.
825b9c1b51eSKate Stone     if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) &&
826b9c1b51eSKate Stone         (value.GetAsUInt32() & 0x01)) {
827a7d7f7cfSOmair Javaid       reg_value &= (~1ull);
828a7d7f7cfSOmair Javaid     }
829a7d7f7cfSOmair Javaid   }
830a7d7f7cfSOmair Javaid 
831a7d7f7cfSOmair Javaid   m_gpr_arm[offset / sizeof(uint32_t)] = reg_value;
8323f3673eaSPavel Labath   return WriteGPR();
833ce26b7a6STamas Berghammer }
834ce26b7a6STamas Berghammer 
ReadGPR()8353f3673eaSPavel Labath Status NativeRegisterContextLinux_arm::ReadGPR() {
836e85e6021STamas Berghammer #ifdef __arm__
8373f3673eaSPavel Labath   return NativeRegisterContextLinux::ReadGPR();
838e85e6021STamas Berghammer #else  // __aarch64__
839e85e6021STamas Berghammer   struct iovec ioVec;
8403f3673eaSPavel Labath   ioVec.iov_base = GetGPRBuffer();
8413f3673eaSPavel Labath   ioVec.iov_len = GetGPRSize();
842e85e6021STamas Berghammer 
8433f3673eaSPavel Labath   return ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
844e85e6021STamas Berghammer #endif // __arm__
845e85e6021STamas Berghammer }
846e85e6021STamas Berghammer 
WriteGPR()8473f3673eaSPavel Labath Status NativeRegisterContextLinux_arm::WriteGPR() {
848e85e6021STamas Berghammer #ifdef __arm__
8493f3673eaSPavel Labath   return NativeRegisterContextLinux::WriteGPR();
850e85e6021STamas Berghammer #else  // __aarch64__
851e85e6021STamas Berghammer   struct iovec ioVec;
8523f3673eaSPavel Labath   ioVec.iov_base = GetGPRBuffer();
8533f3673eaSPavel Labath   ioVec.iov_len = GetGPRSize();
854e85e6021STamas Berghammer 
8553f3673eaSPavel Labath   return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
856e85e6021STamas Berghammer #endif // __arm__
857e85e6021STamas Berghammer }
858e85e6021STamas Berghammer 
ReadFPR()8593f3673eaSPavel Labath Status NativeRegisterContextLinux_arm::ReadFPR() {
860e85e6021STamas Berghammer #ifdef __arm__
861b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(),
8623f3673eaSPavel Labath                                            nullptr, GetFPRBuffer(),
8633f3673eaSPavel Labath                                            GetFPRSize());
864e85e6021STamas Berghammer #else  // __aarch64__
865e85e6021STamas Berghammer   struct iovec ioVec;
8663f3673eaSPavel Labath   ioVec.iov_base = GetFPRBuffer();
8673f3673eaSPavel Labath   ioVec.iov_len = GetFPRSize();
868e85e6021STamas Berghammer 
8693f3673eaSPavel Labath   return ReadRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
870e85e6021STamas Berghammer #endif // __arm__
871ce26b7a6STamas Berghammer }
872ce26b7a6STamas Berghammer 
WriteFPR()8733f3673eaSPavel Labath Status NativeRegisterContextLinux_arm::WriteFPR() {
874e85e6021STamas Berghammer #ifdef __arm__
875b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(),
8763f3673eaSPavel Labath                                            nullptr, GetFPRBuffer(),
8773f3673eaSPavel Labath                                            GetFPRSize());
878e85e6021STamas Berghammer #else  // __aarch64__
879e85e6021STamas Berghammer   struct iovec ioVec;
8803f3673eaSPavel Labath   ioVec.iov_base = GetFPRBuffer();
8813f3673eaSPavel Labath   ioVec.iov_len = GetFPRSize();
882e85e6021STamas Berghammer 
8833f3673eaSPavel Labath   return WriteRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
884e85e6021STamas Berghammer #endif // __arm__
885ce26b7a6STamas Berghammer }
886ce26b7a6STamas Berghammer 
887e85e6021STamas Berghammer #endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
888