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>
23e85e6021STamas Berghammer #include <sys/socket.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>
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 
57b9c1b51eSKate Stone NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
58d37349f3SPavel Labath     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
59*e1d4fb1eSPavel Labath     : NativeRegisterContextRegisterInfo(native_thread,
60*e1d4fb1eSPavel Labath                                         new RegisterInfoPOSIX_arm(target_arch)),
61*e1d4fb1eSPavel 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 
7576953321SMuhammad 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 
79b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount() const {
8076953321SMuhammad Omair Javaid   return GetRegisterInfo().GetRegisterSetCount();
813f57216cSOmair Javaid }
823f57216cSOmair Javaid 
83b9c1b51eSKate 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 *
91b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index) const {
9276953321SMuhammad Omair Javaid   return GetRegisterInfo().GetRegisterSet(set_index);
933f57216cSOmair Javaid }
943f57216cSOmair Javaid 
9597206d57SZachary Turner Status
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
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;
185b9c1b51eSKate Stone     switch (reg_info->byte_size) {
1863f57216cSOmair Javaid     case 2:
1873f57216cSOmair Javaid       *(uint16_t *)dst = reg_value.GetAsUInt16();
1883f57216cSOmair Javaid       break;
1893f57216cSOmair Javaid     case 4:
1903f57216cSOmair Javaid       *(uint32_t *)dst = reg_value.GetAsUInt32();
1913f57216cSOmair Javaid       break;
1923f57216cSOmair Javaid     case 8:
1933f57216cSOmair Javaid       *(uint64_t *)dst = reg_value.GetAsUInt64();
1943f57216cSOmair Javaid       break;
1953f57216cSOmair Javaid     default:
1963f57216cSOmair Javaid       assert(false && "Unhandled data size.");
19797206d57SZachary Turner       return Status("unhandled register data size %" PRIu32,
198b9c1b51eSKate Stone                     reg_info->byte_size);
1993f57216cSOmair Javaid     }
2003f57216cSOmair Javaid 
20197206d57SZachary Turner     Status error = WriteFPR();
202068f8a7eSTamas Berghammer     if (error.Fail())
203068f8a7eSTamas Berghammer       return error;
2043f57216cSOmair Javaid 
20597206d57SZachary Turner     return Status();
2063f57216cSOmair Javaid   }
2073f57216cSOmair Javaid 
20897206d57SZachary Turner   return Status("failed - register wasn't recognized to be a GPR or an FPR, "
209b9c1b51eSKate Stone                 "write strategy unknown");
2103f57216cSOmair Javaid }
2113f57216cSOmair Javaid 
21297206d57SZachary Turner Status NativeRegisterContextLinux_arm::ReadAllRegisterValues(
213b9c1b51eSKate Stone     lldb::DataBufferSP &data_sp) {
21497206d57SZachary Turner   Status error;
2153f57216cSOmair Javaid 
2163f57216cSOmair Javaid   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
217068f8a7eSTamas Berghammer   error = ReadGPR();
218068f8a7eSTamas Berghammer   if (error.Fail())
2193f57216cSOmair Javaid     return error;
2203f57216cSOmair Javaid 
221068f8a7eSTamas Berghammer   error = ReadFPR();
222068f8a7eSTamas Berghammer   if (error.Fail())
2233f57216cSOmair Javaid     return error;
2243f57216cSOmair Javaid 
2253f57216cSOmair Javaid   uint8_t *dst = data_sp->GetBytes();
2263f57216cSOmair Javaid   ::memcpy(dst, &m_gpr_arm, GetGPRSize());
2273f57216cSOmair Javaid   dst += GetGPRSize();
2283f57216cSOmair Javaid   ::memcpy(dst, &m_fpr, sizeof(m_fpr));
2293f57216cSOmair Javaid 
2303f57216cSOmair Javaid   return error;
2313f57216cSOmair Javaid }
2323f57216cSOmair Javaid 
23397206d57SZachary Turner Status NativeRegisterContextLinux_arm::WriteAllRegisterValues(
234b9c1b51eSKate Stone     const lldb::DataBufferSP &data_sp) {
23597206d57SZachary Turner   Status error;
2363f57216cSOmair Javaid 
237b9c1b51eSKate Stone   if (!data_sp) {
238b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
239b9c1b51eSKate Stone         "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided",
240b9c1b51eSKate Stone         __FUNCTION__);
2413f57216cSOmair Javaid     return error;
2423f57216cSOmair Javaid   }
2433f57216cSOmair Javaid 
244b9c1b51eSKate Stone   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
245b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
246b9c1b51eSKate Stone         "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched "
247b9c1b51eSKate Stone         "data size, expected %" PRIu64 ", actual %" PRIu64,
248b9c1b51eSKate Stone         __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize());
2493f57216cSOmair Javaid     return error;
2503f57216cSOmair Javaid   }
2513f57216cSOmair Javaid 
2523f57216cSOmair Javaid   uint8_t *src = data_sp->GetBytes();
253b9c1b51eSKate Stone   if (src == nullptr) {
254b9c1b51eSKate Stone     error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s "
255b9c1b51eSKate Stone                                    "DataBuffer::GetBytes() returned a null "
256b9c1b51eSKate Stone                                    "pointer",
257b9c1b51eSKate Stone                                    __FUNCTION__);
2583f57216cSOmair Javaid     return error;
2593f57216cSOmair Javaid   }
2603f57216cSOmair Javaid   ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize());
2613f57216cSOmair Javaid 
262068f8a7eSTamas Berghammer   error = WriteGPR();
263068f8a7eSTamas Berghammer   if (error.Fail())
2643f57216cSOmair Javaid     return error;
2653f57216cSOmair Javaid 
2663f57216cSOmair Javaid   src += GetRegisterInfoInterface().GetGPRSize();
2673f57216cSOmair Javaid   ::memcpy(&m_fpr, src, sizeof(m_fpr));
2683f57216cSOmair Javaid 
269068f8a7eSTamas Berghammer   error = WriteFPR();
2703f57216cSOmair Javaid   if (error.Fail())
2713f57216cSOmair Javaid     return error;
2723f57216cSOmair Javaid 
2733f57216cSOmair Javaid   return error;
2743f57216cSOmair Javaid }
2753f57216cSOmair Javaid 
276b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const {
27776953321SMuhammad Omair Javaid   if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
27876953321SMuhammad Omair Javaid       RegisterInfoPOSIX_arm::GPRegSet)
27976953321SMuhammad Omair Javaid     return true;
28076953321SMuhammad Omair Javaid   return false;
2813f57216cSOmair Javaid }
2823f57216cSOmair Javaid 
283b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const {
28476953321SMuhammad Omair Javaid   if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
28576953321SMuhammad Omair Javaid       RegisterInfoPOSIX_arm::FPRegSet)
28676953321SMuhammad Omair Javaid     return true;
28776953321SMuhammad Omair Javaid   return false;
2883f57216cSOmair Javaid }
2893f57216cSOmair Javaid 
290d5ffbad2SOmair Javaid uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
291d5ffbad2SOmair Javaid   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
292d5ffbad2SOmair Javaid 
29363e5fb76SJonas Devlieghere   LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
294d5ffbad2SOmair Javaid 
29597206d57SZachary Turner   Status error;
296d5ffbad2SOmair Javaid 
297d5ffbad2SOmair Javaid   // Read hardware breakpoint and watchpoint information.
298d5ffbad2SOmair Javaid   error = ReadHardwareDebugInfo();
299d5ffbad2SOmair Javaid 
300d5ffbad2SOmair Javaid   if (error.Fail())
301d5ffbad2SOmair Javaid     return 0;
302d5ffbad2SOmair Javaid 
303d5ffbad2SOmair Javaid   LLDB_LOG(log, "{0}", m_max_hbp_supported);
304d5ffbad2SOmair Javaid   return m_max_hbp_supported;
305d5ffbad2SOmair Javaid }
306d5ffbad2SOmair Javaid 
3072441aecdSOmair Javaid uint32_t
308b9c1b51eSKate Stone NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
309b9c1b51eSKate Stone                                                       size_t size) {
310d5ffbad2SOmair Javaid   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
311ea1b6b17SPavel Labath   LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
3122441aecdSOmair Javaid 
3132441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
31497206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
3152441aecdSOmair Javaid 
3162441aecdSOmair Javaid   if (error.Fail())
3172441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
3182441aecdSOmair Javaid 
3192441aecdSOmair Javaid   uint32_t control_value = 0, bp_index = 0;
3202441aecdSOmair Javaid 
321d5ffbad2SOmair Javaid   // Setup address and control values.
322d5ffbad2SOmair Javaid   // Use size to get a hint of arm vs thumb modes.
323d5ffbad2SOmair Javaid   switch (size) {
324d5ffbad2SOmair Javaid   case 2:
325d5ffbad2SOmair Javaid     control_value = (0x3 << 5) | 7;
326d5ffbad2SOmair Javaid     addr &= ~1;
327d5ffbad2SOmair Javaid     break;
328d5ffbad2SOmair Javaid   case 4:
329d5ffbad2SOmair Javaid     control_value = (0xfu << 5) | 7;
330d5ffbad2SOmair Javaid     addr &= ~3;
331d5ffbad2SOmair Javaid     break;
332d5ffbad2SOmair Javaid   default:
3332441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
334d5ffbad2SOmair Javaid   }
3352441aecdSOmair Javaid 
336d5ffbad2SOmair Javaid   // Iterate over stored breakpoints and find a free bp_index
3372441aecdSOmair Javaid   bp_index = LLDB_INVALID_INDEX32;
338b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
339b9c1b51eSKate Stone     if ((m_hbr_regs[i].control & 1) == 0) {
3402441aecdSOmair Javaid       bp_index = i; // Mark last free slot
341d5ffbad2SOmair Javaid     } else if (m_hbr_regs[i].address == addr) {
342d5ffbad2SOmair Javaid       return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
3432441aecdSOmair Javaid     }
3442441aecdSOmair Javaid   }
3452441aecdSOmair Javaid 
3462441aecdSOmair Javaid   if (bp_index == LLDB_INVALID_INDEX32)
3472441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
3482441aecdSOmair Javaid 
349d5ffbad2SOmair Javaid   // Update breakpoint in local cache
350d5ffbad2SOmair Javaid   m_hbr_regs[bp_index].real_addr = addr;
3512441aecdSOmair Javaid   m_hbr_regs[bp_index].address = addr;
3522441aecdSOmair Javaid   m_hbr_regs[bp_index].control = control_value;
3532441aecdSOmair Javaid 
3542441aecdSOmair Javaid   // PTRACE call to set corresponding hardware breakpoint register.
3552441aecdSOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
3562441aecdSOmair Javaid 
357b9c1b51eSKate Stone   if (error.Fail()) {
358d5510d1eSOmair Javaid     m_hbr_regs[bp_index].address = 0;
359d5510d1eSOmair Javaid     m_hbr_regs[bp_index].control &= ~1;
360d5510d1eSOmair Javaid 
3612441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
3622441aecdSOmair Javaid   }
3632441aecdSOmair Javaid 
3642441aecdSOmair Javaid   return bp_index;
3652441aecdSOmair Javaid }
3662441aecdSOmair Javaid 
367b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
368d5ffbad2SOmair Javaid   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
369ea1b6b17SPavel Labath   LLDB_LOG(log, "hw_idx: {0}", hw_idx);
3702441aecdSOmair Javaid 
3712441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
37297206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
3732441aecdSOmair Javaid 
3742441aecdSOmair Javaid   if (error.Fail())
3754aa984c1SOmair Javaid     return false;
3762441aecdSOmair Javaid 
3772441aecdSOmair Javaid   if (hw_idx >= m_max_hbp_supported)
3782441aecdSOmair Javaid     return false;
3792441aecdSOmair Javaid 
380d5510d1eSOmair Javaid   // Create a backup we can revert to in case of failure.
381d5510d1eSOmair Javaid   lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
382d5510d1eSOmair Javaid   uint32_t tempControl = m_hbr_regs[hw_idx].control;
383d5510d1eSOmair Javaid 
3842441aecdSOmair Javaid   m_hbr_regs[hw_idx].control &= ~1;
3852441aecdSOmair Javaid   m_hbr_regs[hw_idx].address = 0;
3862441aecdSOmair Javaid 
3872441aecdSOmair Javaid   // PTRACE call to clear corresponding hardware breakpoint register.
388d5ffbad2SOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
3892441aecdSOmair Javaid 
390b9c1b51eSKate Stone   if (error.Fail()) {
391d5510d1eSOmair Javaid     m_hbr_regs[hw_idx].control = tempControl;
392d5510d1eSOmair Javaid     m_hbr_regs[hw_idx].address = tempAddr;
393d5510d1eSOmair Javaid 
3944aa984c1SOmair Javaid     return false;
395d5510d1eSOmair Javaid   }
3962441aecdSOmair Javaid 
3972441aecdSOmair Javaid   return true;
3982441aecdSOmair Javaid }
3992441aecdSOmair Javaid 
40097206d57SZachary Turner Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
401d5ffbad2SOmair Javaid     uint32_t &bp_index, lldb::addr_t trap_addr) {
402d5ffbad2SOmair Javaid   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
403d5ffbad2SOmair Javaid 
40463e5fb76SJonas Devlieghere   LLDB_LOGF(log, "NativeRegisterContextLinux_arm64::%s()", __FUNCTION__);
405d5ffbad2SOmair Javaid 
406d5ffbad2SOmair Javaid   lldb::addr_t break_addr;
407d5ffbad2SOmair Javaid 
408d5ffbad2SOmair Javaid   for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
409d5ffbad2SOmair Javaid     break_addr = m_hbr_regs[bp_index].address;
410d5ffbad2SOmair Javaid 
411d5ffbad2SOmair Javaid     if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
412d5ffbad2SOmair Javaid       m_hbr_regs[bp_index].hit_addr = trap_addr;
41397206d57SZachary Turner       return Status();
414d5ffbad2SOmair Javaid     }
415d5ffbad2SOmair Javaid   }
416d5ffbad2SOmair Javaid 
417d5ffbad2SOmair Javaid   bp_index = LLDB_INVALID_INDEX32;
41897206d57SZachary Turner   return Status();
419d5ffbad2SOmair Javaid }
420d5ffbad2SOmair Javaid 
42197206d57SZachary Turner Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
422d5ffbad2SOmair Javaid   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
423d5ffbad2SOmair Javaid 
42463e5fb76SJonas Devlieghere   LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
425d5ffbad2SOmair Javaid 
42697206d57SZachary Turner   Status error;
427d5ffbad2SOmair Javaid 
428d5ffbad2SOmair Javaid   // Read hardware breakpoint and watchpoint information.
429d5ffbad2SOmair Javaid   error = ReadHardwareDebugInfo();
430d5ffbad2SOmair Javaid 
431d5ffbad2SOmair Javaid   if (error.Fail())
432d5ffbad2SOmair Javaid     return error;
433d5ffbad2SOmair Javaid 
434d5ffbad2SOmair Javaid   lldb::addr_t tempAddr = 0;
435d5ffbad2SOmair Javaid   uint32_t tempControl = 0;
436d5ffbad2SOmair Javaid 
437d5ffbad2SOmair Javaid   for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
438d5ffbad2SOmair Javaid     if (m_hbr_regs[i].control & 0x01) {
439d5ffbad2SOmair Javaid       // Create a backup we can revert to in case of failure.
440d5ffbad2SOmair Javaid       tempAddr = m_hbr_regs[i].address;
441d5ffbad2SOmair Javaid       tempControl = m_hbr_regs[i].control;
442d5ffbad2SOmair Javaid 
443d5ffbad2SOmair Javaid       // Clear breakpoints in local cache
444d5ffbad2SOmair Javaid       m_hbr_regs[i].control &= ~1;
445d5ffbad2SOmair Javaid       m_hbr_regs[i].address = 0;
446d5ffbad2SOmair Javaid 
447d5ffbad2SOmair Javaid       // Ptrace call to update hardware debug registers
448d5ffbad2SOmair Javaid       error = WriteHardwareDebugRegs(eDREGTypeBREAK, i);
449d5ffbad2SOmair Javaid 
450d5ffbad2SOmair Javaid       if (error.Fail()) {
451d5ffbad2SOmair Javaid         m_hbr_regs[i].control = tempControl;
452d5ffbad2SOmair Javaid         m_hbr_regs[i].address = tempAddr;
453d5ffbad2SOmair Javaid 
454d5ffbad2SOmair Javaid         return error;
455d5ffbad2SOmair Javaid       }
456d5ffbad2SOmair Javaid     }
457d5ffbad2SOmair Javaid   }
458d5ffbad2SOmair Javaid 
45997206d57SZachary Turner   return Status();
4602441aecdSOmair Javaid }
4612441aecdSOmair Javaid 
462b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
463ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
4642441aecdSOmair Javaid 
4652441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
46697206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
4672441aecdSOmair Javaid 
4682441aecdSOmair Javaid   if (error.Fail())
46962661473SOmair Javaid     return 0;
4702441aecdSOmair Javaid 
471ea1b6b17SPavel Labath   LLDB_LOG(log, "{0}", m_max_hwp_supported);
4722441aecdSOmair Javaid   return m_max_hwp_supported;
4732441aecdSOmair Javaid }
4742441aecdSOmair Javaid 
475b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
476b9c1b51eSKate Stone     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
477ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
478ea1b6b17SPavel Labath   LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
479ea1b6b17SPavel Labath            watch_flags);
4802441aecdSOmair Javaid 
4812441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
48297206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
4832441aecdSOmair Javaid 
4842441aecdSOmair Javaid   if (error.Fail())
4852441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
4862441aecdSOmair Javaid 
4872441aecdSOmair Javaid   uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
488c6dc90efSOmair Javaid   lldb::addr_t real_addr = addr;
4892441aecdSOmair Javaid 
49005097246SAdrian Prantl   // Check if we are setting watchpoint other than read/write/access Also
49105097246SAdrian Prantl   // update watchpoint flag to match Arm write-read bit configuration.
492b9c1b51eSKate Stone   switch (watch_flags) {
4932441aecdSOmair Javaid   case 1:
4942441aecdSOmair Javaid     watch_flags = 2;
4952441aecdSOmair Javaid     break;
4962441aecdSOmair Javaid   case 2:
4972441aecdSOmair Javaid     watch_flags = 1;
4982441aecdSOmair Javaid     break;
4992441aecdSOmair Javaid   case 3:
5002441aecdSOmair Javaid     break;
5012441aecdSOmair Javaid   default:
5022441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5032441aecdSOmair Javaid   }
5042441aecdSOmair Javaid 
5052441aecdSOmair Javaid   // Can't watch zero bytes
5062441aecdSOmair Javaid   // Can't watch more than 4 bytes per WVR/WCR pair
5072441aecdSOmair Javaid 
5082441aecdSOmair Javaid   if (size == 0 || size > 4)
5092441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5102441aecdSOmair Javaid 
51105097246SAdrian Prantl   // Check 4-byte alignment for hardware watchpoint target address. Below is a
51205097246SAdrian Prantl   // hack to recalculate address and size in order to make sure we can watch
513e9264b74SKazuaki Ishizaki   // non 4-byte aligned addresses as well.
514b9c1b51eSKate Stone   if (addr & 0x03) {
515c6dc90efSOmair Javaid     uint8_t watch_mask = (addr & 0x03) + size;
516c6dc90efSOmair Javaid 
517c6dc90efSOmair Javaid     if (watch_mask > 0x04)
518c6dc90efSOmair Javaid       return LLDB_INVALID_INDEX32;
519c6dc90efSOmair Javaid     else if (watch_mask <= 0x02)
520c6dc90efSOmair Javaid       size = 2;
521c6dc90efSOmair Javaid     else if (watch_mask <= 0x04)
522c6dc90efSOmair Javaid       size = 4;
523c6dc90efSOmair Javaid 
524c6dc90efSOmair Javaid     addr = addr & (~0x03);
525c6dc90efSOmair Javaid   }
526c6dc90efSOmair Javaid 
5272441aecdSOmair Javaid   // We can only watch up to four bytes that follow a 4 byte aligned address
5282441aecdSOmair Javaid   // per watchpoint register pair, so make sure we can properly encode this.
5292441aecdSOmair Javaid   addr_word_offset = addr % 4;
5302441aecdSOmair Javaid   byte_mask = ((1u << size) - 1u) << addr_word_offset;
5312441aecdSOmair Javaid 
5322441aecdSOmair Javaid   // Check if we need multiple watchpoint register
5332441aecdSOmair Javaid   if (byte_mask > 0xfu)
5342441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5352441aecdSOmair Javaid 
5362441aecdSOmair Javaid   // Setup control value
5372441aecdSOmair Javaid   // Make the byte_mask into a valid Byte Address Select mask
5382441aecdSOmair Javaid   control_value = byte_mask << 5;
5392441aecdSOmair Javaid 
5402441aecdSOmair Javaid   // Turn on appropriate watchpoint flags read or write
5412441aecdSOmair Javaid   control_value |= (watch_flags << 3);
5422441aecdSOmair Javaid 
5432441aecdSOmair Javaid   // Enable this watchpoint and make it stop in privileged or user mode;
5442441aecdSOmair Javaid   control_value |= 7;
5452441aecdSOmair Javaid 
5462441aecdSOmair Javaid   // Make sure bits 1:0 are clear in our address
5472441aecdSOmair Javaid   addr &= ~((lldb::addr_t)3);
5482441aecdSOmair Javaid 
54905ac4c44SOmair Javaid   // Iterate over stored watchpoints and find a free wp_index
5502441aecdSOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
551b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
552b9c1b51eSKate Stone     if ((m_hwp_regs[i].control & 1) == 0) {
5532441aecdSOmair Javaid       wp_index = i; // Mark last free slot
55405ac4c44SOmair Javaid     } else if (m_hwp_regs[i].address == addr) {
55505ac4c44SOmair Javaid       return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
5562441aecdSOmair Javaid     }
5572441aecdSOmair Javaid   }
5582441aecdSOmair Javaid 
5592441aecdSOmair Javaid   if (wp_index == LLDB_INVALID_INDEX32)
5602441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5612441aecdSOmair Javaid 
5622441aecdSOmair Javaid   // Update watchpoint in local cache
563c6dc90efSOmair Javaid   m_hwp_regs[wp_index].real_addr = real_addr;
5642441aecdSOmair Javaid   m_hwp_regs[wp_index].address = addr;
5652441aecdSOmair Javaid   m_hwp_regs[wp_index].control = control_value;
5662441aecdSOmair Javaid 
5672441aecdSOmair Javaid   // PTRACE call to set corresponding watchpoint register.
5682441aecdSOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
5692441aecdSOmair Javaid 
570b9c1b51eSKate Stone   if (error.Fail()) {
571d5510d1eSOmair Javaid     m_hwp_regs[wp_index].address = 0;
572d5510d1eSOmair Javaid     m_hwp_regs[wp_index].control &= ~1;
573d5510d1eSOmair Javaid 
5742441aecdSOmair Javaid     return LLDB_INVALID_INDEX32;
5752441aecdSOmair Javaid   }
5762441aecdSOmair Javaid 
5772441aecdSOmair Javaid   return wp_index;
5782441aecdSOmair Javaid }
5792441aecdSOmair Javaid 
580b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
581b9c1b51eSKate Stone     uint32_t wp_index) {
582ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
583ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
5842441aecdSOmair Javaid 
5852441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
58697206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
5872441aecdSOmair Javaid 
5882441aecdSOmair Javaid   if (error.Fail())
5894aa984c1SOmair Javaid     return false;
5902441aecdSOmair Javaid 
5912441aecdSOmair Javaid   if (wp_index >= m_max_hwp_supported)
5922441aecdSOmair Javaid     return false;
5932441aecdSOmair Javaid 
594d5510d1eSOmair Javaid   // Create a backup we can revert to in case of failure.
595d5510d1eSOmair Javaid   lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
596d5510d1eSOmair Javaid   uint32_t tempControl = m_hwp_regs[wp_index].control;
597d5510d1eSOmair Javaid 
5982441aecdSOmair Javaid   // Update watchpoint in local cache
5992441aecdSOmair Javaid   m_hwp_regs[wp_index].control &= ~1;
6002441aecdSOmair Javaid   m_hwp_regs[wp_index].address = 0;
6012441aecdSOmair Javaid 
6022441aecdSOmair Javaid   // Ptrace call to update hardware debug registers
6032441aecdSOmair Javaid   error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
6042441aecdSOmair Javaid 
605b9c1b51eSKate Stone   if (error.Fail()) {
606d5510d1eSOmair Javaid     m_hwp_regs[wp_index].control = tempControl;
607d5510d1eSOmair Javaid     m_hwp_regs[wp_index].address = tempAddr;
608d5510d1eSOmair Javaid 
6092441aecdSOmair Javaid     return false;
610d5510d1eSOmair Javaid   }
6112441aecdSOmair Javaid 
6122441aecdSOmair Javaid   return true;
6132441aecdSOmair Javaid }
6142441aecdSOmair Javaid 
61597206d57SZachary Turner Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
6162441aecdSOmair Javaid   // Read hardware breakpoint and watchpoint information.
61797206d57SZachary Turner   Status error = ReadHardwareDebugInfo();
6182441aecdSOmair Javaid 
6192441aecdSOmair Javaid   if (error.Fail())
6202441aecdSOmair Javaid     return error;
6212441aecdSOmair Javaid 
622d5510d1eSOmair Javaid   lldb::addr_t tempAddr = 0;
62305ac4c44SOmair Javaid   uint32_t tempControl = 0;
624d5510d1eSOmair Javaid 
625b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
626b9c1b51eSKate Stone     if (m_hwp_regs[i].control & 0x01) {
627d5510d1eSOmair Javaid       // Create a backup we can revert to in case of failure.
628d5510d1eSOmair Javaid       tempAddr = m_hwp_regs[i].address;
629d5510d1eSOmair Javaid       tempControl = m_hwp_regs[i].control;
630d5510d1eSOmair Javaid 
6312441aecdSOmair Javaid       // Clear watchpoints in local cache
6322441aecdSOmair Javaid       m_hwp_regs[i].control &= ~1;
6332441aecdSOmair Javaid       m_hwp_regs[i].address = 0;
6342441aecdSOmair Javaid 
6352441aecdSOmair Javaid       // Ptrace call to update hardware debug registers
6362441aecdSOmair Javaid       error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
6372441aecdSOmair Javaid 
638b9c1b51eSKate Stone       if (error.Fail()) {
639d5510d1eSOmair Javaid         m_hwp_regs[i].control = tempControl;
640d5510d1eSOmair Javaid         m_hwp_regs[i].address = tempAddr;
641d5510d1eSOmair Javaid 
6422441aecdSOmair Javaid         return error;
6432441aecdSOmair Javaid       }
6442441aecdSOmair Javaid     }
645d5510d1eSOmair Javaid   }
6462441aecdSOmair Javaid 
64797206d57SZachary Turner   return Status();
6482441aecdSOmair Javaid }
6492441aecdSOmair Javaid 
650b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) {
651ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
652ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
6532441aecdSOmair Javaid 
654b9c1b51eSKate Stone   switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
6552441aecdSOmair Javaid   case 0x01:
6562441aecdSOmair Javaid     return 1;
6572441aecdSOmair Javaid   case 0x03:
6582441aecdSOmair Javaid     return 2;
6592441aecdSOmair Javaid   case 0x07:
6602441aecdSOmair Javaid     return 3;
6612441aecdSOmair Javaid   case 0x0f:
6622441aecdSOmair Javaid     return 4;
6632441aecdSOmair Javaid   default:
6642441aecdSOmair Javaid     return 0;
6652441aecdSOmair Javaid   }
6662441aecdSOmair Javaid }
667b9c1b51eSKate Stone bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) {
668ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
669ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
6702441aecdSOmair Javaid 
6712441aecdSOmair Javaid   if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
6722441aecdSOmair Javaid     return true;
6732441aecdSOmair Javaid   else
6742441aecdSOmair Javaid     return false;
6752441aecdSOmair Javaid }
6762441aecdSOmair Javaid 
67797206d57SZachary Turner Status
67897206d57SZachary Turner NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index,
67997206d57SZachary Turner                                                       lldb::addr_t trap_addr) {
680ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
681ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
6822441aecdSOmair Javaid 
6832441aecdSOmair Javaid   uint32_t watch_size;
6842441aecdSOmair Javaid   lldb::addr_t watch_addr;
6852441aecdSOmair Javaid 
686b9c1b51eSKate Stone   for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
6872441aecdSOmair Javaid     watch_size = GetWatchpointSize(wp_index);
6882441aecdSOmair Javaid     watch_addr = m_hwp_regs[wp_index].address;
6892441aecdSOmair Javaid 
69005ac4c44SOmair Javaid     if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
69105ac4c44SOmair Javaid         trap_addr < watch_addr + watch_size) {
692c6dc90efSOmair Javaid       m_hwp_regs[wp_index].hit_addr = trap_addr;
69397206d57SZachary Turner       return Status();
6942441aecdSOmair Javaid     }
6952441aecdSOmair Javaid   }
6962441aecdSOmair Javaid 
6972441aecdSOmair Javaid   wp_index = LLDB_INVALID_INDEX32;
69897206d57SZachary Turner   return Status();
6992441aecdSOmair Javaid }
7002441aecdSOmair Javaid 
7012441aecdSOmair Javaid lldb::addr_t
702b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) {
703ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
704ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
7052441aecdSOmair Javaid 
7062441aecdSOmair Javaid   if (wp_index >= m_max_hwp_supported)
7072441aecdSOmair Javaid     return LLDB_INVALID_ADDRESS;
7082441aecdSOmair Javaid 
7092441aecdSOmair Javaid   if (WatchpointIsEnabled(wp_index))
710c6dc90efSOmair Javaid     return m_hwp_regs[wp_index].real_addr;
711c6dc90efSOmair Javaid   else
712c6dc90efSOmair Javaid     return LLDB_INVALID_ADDRESS;
713c6dc90efSOmair Javaid }
714c6dc90efSOmair Javaid 
715c6dc90efSOmair Javaid lldb::addr_t
716b9c1b51eSKate Stone NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) {
717ea1b6b17SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
718ea1b6b17SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
719c6dc90efSOmair Javaid 
720c6dc90efSOmair Javaid   if (wp_index >= m_max_hwp_supported)
721c6dc90efSOmair Javaid     return LLDB_INVALID_ADDRESS;
722c6dc90efSOmair Javaid 
723c6dc90efSOmair Javaid   if (WatchpointIsEnabled(wp_index))
724c6dc90efSOmair Javaid     return m_hwp_regs[wp_index].hit_addr;
7252441aecdSOmair Javaid   else
7262441aecdSOmair Javaid     return LLDB_INVALID_ADDRESS;
7272441aecdSOmair Javaid }
7282441aecdSOmair Javaid 
72997206d57SZachary Turner Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
73097206d57SZachary Turner   Status error;
7312441aecdSOmair Javaid 
732b9c1b51eSKate Stone   if (!m_refresh_hwdebug_info) {
73397206d57SZachary Turner     return Status();
7342441aecdSOmair Javaid   }
7352441aecdSOmair Javaid 
7362441aecdSOmair Javaid   unsigned int cap_val;
7372441aecdSOmair Javaid 
738b9c1b51eSKate Stone   error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(),
739b9c1b51eSKate Stone                                             nullptr, &cap_val,
740b9c1b51eSKate Stone                                             sizeof(unsigned int));
7412441aecdSOmair Javaid 
7422441aecdSOmair Javaid   if (error.Fail())
7432441aecdSOmair Javaid     return error;
7442441aecdSOmair Javaid 
7452441aecdSOmair Javaid   m_max_hwp_supported = (cap_val >> 8) & 0xff;
7462441aecdSOmair Javaid   m_max_hbp_supported = cap_val & 0xff;
7472441aecdSOmair Javaid   m_refresh_hwdebug_info = false;
7482441aecdSOmair Javaid 
7492441aecdSOmair Javaid   return error;
7502441aecdSOmair Javaid }
7512441aecdSOmair Javaid 
75297206d57SZachary Turner Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType,
753b9c1b51eSKate Stone                                                               int hwb_index) {
75497206d57SZachary Turner   Status error;
7552441aecdSOmair Javaid 
7562441aecdSOmair Javaid   lldb::addr_t *addr_buf;
7572441aecdSOmair Javaid   uint32_t *ctrl_buf;
7582441aecdSOmair Javaid 
759b9c1b51eSKate Stone   if (hwbType == eDREGTypeWATCH) {
7602441aecdSOmair Javaid     addr_buf = &m_hwp_regs[hwb_index].address;
7612441aecdSOmair Javaid     ctrl_buf = &m_hwp_regs[hwb_index].control;
7622441aecdSOmair Javaid 
763b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
764b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
765b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf,
766b9c1b51eSKate Stone         sizeof(unsigned int));
7672441aecdSOmair Javaid 
7682441aecdSOmair Javaid     if (error.Fail())
7692441aecdSOmair Javaid       return error;
7702441aecdSOmair Javaid 
771b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
772b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
773b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
774b9c1b51eSKate Stone         sizeof(unsigned int));
775b9c1b51eSKate Stone   } else {
776d5ffbad2SOmair Javaid     addr_buf = &m_hbr_regs[hwb_index].address;
777d5ffbad2SOmair Javaid     ctrl_buf = &m_hbr_regs[hwb_index].control;
7782441aecdSOmair Javaid 
779b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
780b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
781b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf,
782b9c1b51eSKate Stone         sizeof(unsigned int));
7832441aecdSOmair Javaid 
7842441aecdSOmair Javaid     if (error.Fail())
7852441aecdSOmair Javaid       return error;
7862441aecdSOmair Javaid 
787b9c1b51eSKate Stone     error = NativeProcessLinux::PtraceWrapper(
788b9c1b51eSKate Stone         PTRACE_SETHBPREGS, m_thread.GetID(),
789b9c1b51eSKate Stone         (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
790b9c1b51eSKate Stone         sizeof(unsigned int));
7912441aecdSOmair Javaid   }
7922441aecdSOmair Javaid 
7932441aecdSOmair Javaid   return error;
7942441aecdSOmair Javaid }
795c40e7b17STamas Berghammer 
796b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
797b9c1b51eSKate Stone     const RegisterInfo *reg_info) const {
79876953321SMuhammad Omair Javaid   return reg_info->byte_offset - GetGPRSize();
799c40e7b17STamas Berghammer }
800c40e7b17STamas Berghammer 
80197206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoReadRegisterValue(
802b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, uint32_t size,
803b9c1b51eSKate Stone     RegisterValue &value) {
804b9c1b51eSKate Stone   // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android
80505097246SAdrian Prantl   // devices (always return "Bad address"). To avoid using PTRACE_PEEKUSER we
80605097246SAdrian Prantl   // read out the full GPR register set instead. This approach is about 4 times
807e9264b74SKazuaki Ishizaki   // slower but the performance overhead is negligible in comparison to
80805097246SAdrian Prantl   // processing time in lldb-server.
809e85e6021STamas Berghammer   assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
810e85e6021STamas Berghammer   if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
81197206d57SZachary Turner     return Status("Register isn't fit into the size of the GPR area");
812e85e6021STamas Berghammer 
8133f3673eaSPavel Labath   Status error = ReadGPR();
814e85e6021STamas Berghammer   if (error.Fail())
815e85e6021STamas Berghammer     return error;
816e85e6021STamas Berghammer 
817e85e6021STamas Berghammer   value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]);
81897206d57SZachary Turner   return Status();
819e85e6021STamas Berghammer }
820e85e6021STamas Berghammer 
82197206d57SZachary Turner Status NativeRegisterContextLinux_arm::DoWriteRegisterValue(
822b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, const RegisterValue &value) {
823b9c1b51eSKate Stone   // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android
82405097246SAdrian Prantl   // devices (always return "Bad address"). To avoid using PTRACE_POKEUSER we
82505097246SAdrian Prantl   // read out the full GPR register set, modify the requested register and
82605097246SAdrian Prantl   // write it back. This approach is about 4 times slower but the performance
827e9264b74SKazuaki Ishizaki   // overhead is negligible in comparison to processing time in lldb-server.
828ce26b7a6STamas Berghammer   assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
829ce26b7a6STamas Berghammer   if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
83097206d57SZachary Turner     return Status("Register isn't fit into the size of the GPR area");
831ce26b7a6STamas Berghammer 
8323f3673eaSPavel Labath   Status error = ReadGPR();
833ce26b7a6STamas Berghammer   if (error.Fail())
834ce26b7a6STamas Berghammer     return error;
835ce26b7a6STamas Berghammer 
836a7d7f7cfSOmair Javaid   uint32_t reg_value = value.GetAsUInt32();
837a7d7f7cfSOmair Javaid   // As precaution for an undefined behavior encountered while setting PC we
838a7d7f7cfSOmair Javaid   // will clear thumb bit of new PC if we are already in thumb mode; that is
839a7d7f7cfSOmair Javaid   // CPSR thumb mode bit is set.
840b9c1b51eSKate Stone   if (offset / sizeof(uint32_t) == gpr_pc_arm) {
84105097246SAdrian Prantl     // Check if we are already in thumb mode and thumb bit of current PC is
84205097246SAdrian Prantl     // read out to be zero and thumb bit of next PC is read out to be one.
843b9c1b51eSKate Stone     if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) &&
844b9c1b51eSKate Stone         (value.GetAsUInt32() & 0x01)) {
845a7d7f7cfSOmair Javaid       reg_value &= (~1ull);
846a7d7f7cfSOmair Javaid     }
847a7d7f7cfSOmair Javaid   }
848a7d7f7cfSOmair Javaid 
849a7d7f7cfSOmair Javaid   m_gpr_arm[offset / sizeof(uint32_t)] = reg_value;
8503f3673eaSPavel Labath   return WriteGPR();
851ce26b7a6STamas Berghammer }
852ce26b7a6STamas Berghammer 
8533f3673eaSPavel Labath Status NativeRegisterContextLinux_arm::ReadGPR() {
854e85e6021STamas Berghammer #ifdef __arm__
8553f3673eaSPavel Labath   return NativeRegisterContextLinux::ReadGPR();
856e85e6021STamas Berghammer #else  // __aarch64__
857e85e6021STamas Berghammer   struct iovec ioVec;
8583f3673eaSPavel Labath   ioVec.iov_base = GetGPRBuffer();
8593f3673eaSPavel Labath   ioVec.iov_len = GetGPRSize();
860e85e6021STamas Berghammer 
8613f3673eaSPavel Labath   return ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
862e85e6021STamas Berghammer #endif // __arm__
863e85e6021STamas Berghammer }
864e85e6021STamas Berghammer 
8653f3673eaSPavel Labath Status NativeRegisterContextLinux_arm::WriteGPR() {
866e85e6021STamas Berghammer #ifdef __arm__
8673f3673eaSPavel Labath   return NativeRegisterContextLinux::WriteGPR();
868e85e6021STamas Berghammer #else  // __aarch64__
869e85e6021STamas Berghammer   struct iovec ioVec;
8703f3673eaSPavel Labath   ioVec.iov_base = GetGPRBuffer();
8713f3673eaSPavel Labath   ioVec.iov_len = GetGPRSize();
872e85e6021STamas Berghammer 
8733f3673eaSPavel Labath   return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
874e85e6021STamas Berghammer #endif // __arm__
875e85e6021STamas Berghammer }
876e85e6021STamas Berghammer 
8773f3673eaSPavel Labath Status NativeRegisterContextLinux_arm::ReadFPR() {
878e85e6021STamas Berghammer #ifdef __arm__
879b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(),
8803f3673eaSPavel Labath                                            nullptr, GetFPRBuffer(),
8813f3673eaSPavel Labath                                            GetFPRSize());
882e85e6021STamas Berghammer #else  // __aarch64__
883e85e6021STamas Berghammer   struct iovec ioVec;
8843f3673eaSPavel Labath   ioVec.iov_base = GetFPRBuffer();
8853f3673eaSPavel Labath   ioVec.iov_len = GetFPRSize();
886e85e6021STamas Berghammer 
8873f3673eaSPavel Labath   return ReadRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
888e85e6021STamas Berghammer #endif // __arm__
889ce26b7a6STamas Berghammer }
890ce26b7a6STamas Berghammer 
8913f3673eaSPavel Labath Status NativeRegisterContextLinux_arm::WriteFPR() {
892e85e6021STamas Berghammer #ifdef __arm__
893b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(),
8943f3673eaSPavel Labath                                            nullptr, GetFPRBuffer(),
8953f3673eaSPavel Labath                                            GetFPRSize());
896e85e6021STamas Berghammer #else  // __aarch64__
897e85e6021STamas Berghammer   struct iovec ioVec;
8983f3673eaSPavel Labath   ioVec.iov_base = GetFPRBuffer();
8993f3673eaSPavel Labath   ioVec.iov_len = GetFPRSize();
900e85e6021STamas Berghammer 
9013f3673eaSPavel Labath   return WriteRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
902e85e6021STamas Berghammer #endif // __arm__
903ce26b7a6STamas Berghammer }
904ce26b7a6STamas Berghammer 
905e85e6021STamas Berghammer #endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
906