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 ®_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 ®_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