1d409305fSDimitry Andric //===-- NativeRegisterContextFreeBSD_arm64.cpp ----------------------------===// 2d409305fSDimitry Andric // 3d409305fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4d409305fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5d409305fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6d409305fSDimitry Andric // 7d409305fSDimitry Andric //===----------------------------------------------------------------------===// 8d409305fSDimitry Andric 9d409305fSDimitry Andric #if defined(__aarch64__) 10d409305fSDimitry Andric 11d409305fSDimitry Andric #include "NativeRegisterContextFreeBSD_arm64.h" 12d409305fSDimitry Andric 13d409305fSDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 14d409305fSDimitry Andric #include "lldb/Utility/RegisterValue.h" 15d409305fSDimitry Andric #include "lldb/Utility/Status.h" 16d409305fSDimitry Andric 17d409305fSDimitry Andric #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" 18d409305fSDimitry Andric #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 19*0fca6ea1SDimitry Andric #include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h" 20d409305fSDimitry Andric #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" 21d409305fSDimitry Andric 22d409305fSDimitry Andric // clang-format off 23d409305fSDimitry Andric #include <sys/param.h> 24d409305fSDimitry Andric #include <sys/ptrace.h> 25d409305fSDimitry Andric #include <sys/types.h> 26d409305fSDimitry Andric // clang-format on 27d409305fSDimitry Andric 28d409305fSDimitry Andric using namespace lldb; 29d409305fSDimitry Andric using namespace lldb_private; 30d409305fSDimitry Andric using namespace lldb_private::process_freebsd; 31d409305fSDimitry Andric 32*0fca6ea1SDimitry Andric // A NativeRegisterContext is constructed per thread, but all threads' registers 33*0fca6ea1SDimitry Andric // will contain the same fields. Therefore this mutex prevents each instance 34*0fca6ea1SDimitry Andric // competing with the other, and subsequent instances from having to detect the 35*0fca6ea1SDimitry Andric // fields all over again. 36*0fca6ea1SDimitry Andric static std::mutex g_register_flags_detector_mutex; 37*0fca6ea1SDimitry Andric static Arm64RegisterFlagsDetector g_register_flags_detector; 38*0fca6ea1SDimitry Andric 39d409305fSDimitry Andric NativeRegisterContextFreeBSD * 40d409305fSDimitry Andric NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( 41*0fca6ea1SDimitry Andric const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) { 42*0fca6ea1SDimitry Andric std::lock_guard<std::mutex> lock(g_register_flags_detector_mutex); 43*0fca6ea1SDimitry Andric if (!g_register_flags_detector.HasDetected()) { 44*0fca6ea1SDimitry Andric NativeProcessFreeBSD &process = native_thread.GetProcess(); 45*0fca6ea1SDimitry Andric g_register_flags_detector.DetectFields( 46*0fca6ea1SDimitry Andric process.GetAuxValue(AuxVector::AUXV_FREEBSD_AT_HWCAP).value_or(0), 47*0fca6ea1SDimitry Andric process.GetAuxValue(AuxVector::AUXV_AT_HWCAP2).value_or(0)); 48*0fca6ea1SDimitry Andric } 49*0fca6ea1SDimitry Andric 50d409305fSDimitry Andric return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread); 51d409305fSDimitry Andric } 52d409305fSDimitry Andric 53d409305fSDimitry Andric NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64( 54*0fca6ea1SDimitry Andric const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) 55d409305fSDimitry Andric : NativeRegisterContextRegisterInfo( 56fe6060f1SDimitry Andric native_thread, new RegisterInfoPOSIX_arm64(target_arch, 0)) 57d409305fSDimitry Andric #ifdef LLDB_HAS_FREEBSD_WATCHPOINT 58d409305fSDimitry Andric , 59d409305fSDimitry Andric m_read_dbreg(false) 60d409305fSDimitry Andric #endif 61d409305fSDimitry Andric { 62*0fca6ea1SDimitry Andric g_register_flags_detector.UpdateRegisterInfo( 63*0fca6ea1SDimitry Andric GetRegisterInfoInterface().GetRegisterInfo(), 64*0fca6ea1SDimitry Andric GetRegisterInfoInterface().GetRegisterCount()); 65*0fca6ea1SDimitry Andric 66d409305fSDimitry Andric ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); 67d409305fSDimitry Andric ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs)); 68d409305fSDimitry Andric } 69d409305fSDimitry Andric 70d409305fSDimitry Andric RegisterInfoPOSIX_arm64 & 71d409305fSDimitry Andric NativeRegisterContextFreeBSD_arm64::GetRegisterInfo() const { 72d409305fSDimitry Andric return static_cast<RegisterInfoPOSIX_arm64 &>(*m_register_info_interface_up); 73d409305fSDimitry Andric } 74d409305fSDimitry Andric 75d409305fSDimitry Andric uint32_t NativeRegisterContextFreeBSD_arm64::GetRegisterSetCount() const { 76d409305fSDimitry Andric return GetRegisterInfo().GetRegisterSetCount(); 77d409305fSDimitry Andric } 78d409305fSDimitry Andric 79d409305fSDimitry Andric const RegisterSet * 80d409305fSDimitry Andric NativeRegisterContextFreeBSD_arm64::GetRegisterSet(uint32_t set_index) const { 81d409305fSDimitry Andric return GetRegisterInfo().GetRegisterSet(set_index); 82d409305fSDimitry Andric } 83d409305fSDimitry Andric 84d409305fSDimitry Andric uint32_t NativeRegisterContextFreeBSD_arm64::GetUserRegisterCount() const { 85d409305fSDimitry Andric uint32_t count = 0; 86d409305fSDimitry Andric for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) 87d409305fSDimitry Andric count += GetRegisterSet(set_index)->num_registers; 88d409305fSDimitry Andric return count; 89d409305fSDimitry Andric } 90d409305fSDimitry Andric 91d409305fSDimitry Andric Status NativeRegisterContextFreeBSD_arm64::ReadRegisterSet(uint32_t set) { 92d409305fSDimitry Andric switch (set) { 93d409305fSDimitry Andric case RegisterInfoPOSIX_arm64::GPRegSet: 94d409305fSDimitry Andric return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), 95d409305fSDimitry Andric m_reg_data.data()); 96d409305fSDimitry Andric case RegisterInfoPOSIX_arm64::FPRegSet: 97d409305fSDimitry Andric return NativeProcessFreeBSD::PtraceWrapper( 98d409305fSDimitry Andric PT_GETFPREGS, m_thread.GetID(), 99d409305fSDimitry Andric m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR)); 100d409305fSDimitry Andric } 101d409305fSDimitry Andric llvm_unreachable("NativeRegisterContextFreeBSD_arm64::ReadRegisterSet"); 102d409305fSDimitry Andric } 103d409305fSDimitry Andric 104d409305fSDimitry Andric Status NativeRegisterContextFreeBSD_arm64::WriteRegisterSet(uint32_t set) { 105d409305fSDimitry Andric switch (set) { 106d409305fSDimitry Andric case RegisterInfoPOSIX_arm64::GPRegSet: 107d409305fSDimitry Andric return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), 108d409305fSDimitry Andric m_reg_data.data()); 109d409305fSDimitry Andric case RegisterInfoPOSIX_arm64::FPRegSet: 110d409305fSDimitry Andric return NativeProcessFreeBSD::PtraceWrapper( 111d409305fSDimitry Andric PT_SETFPREGS, m_thread.GetID(), 112d409305fSDimitry Andric m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR)); 113d409305fSDimitry Andric } 114d409305fSDimitry Andric llvm_unreachable("NativeRegisterContextFreeBSD_arm64::WriteRegisterSet"); 115d409305fSDimitry Andric } 116d409305fSDimitry Andric 117d409305fSDimitry Andric Status 118d409305fSDimitry Andric NativeRegisterContextFreeBSD_arm64::ReadRegister(const RegisterInfo *reg_info, 119d409305fSDimitry Andric RegisterValue ®_value) { 120d409305fSDimitry Andric Status error; 121d409305fSDimitry Andric 122d409305fSDimitry Andric if (!reg_info) { 123d409305fSDimitry Andric error.SetErrorString("reg_info NULL"); 124d409305fSDimitry Andric return error; 125d409305fSDimitry Andric } 126d409305fSDimitry Andric 127d409305fSDimitry Andric const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 128d409305fSDimitry Andric 129d409305fSDimitry Andric if (reg == LLDB_INVALID_REGNUM) 130d409305fSDimitry Andric return Status("no lldb regnum for %s", reg_info && reg_info->name 131d409305fSDimitry Andric ? reg_info->name 132d409305fSDimitry Andric : "<unknown register>"); 133d409305fSDimitry Andric 134d409305fSDimitry Andric uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); 135d409305fSDimitry Andric error = ReadRegisterSet(set); 136d409305fSDimitry Andric if (error.Fail()) 137d409305fSDimitry Andric return error; 138d409305fSDimitry Andric 139d409305fSDimitry Andric assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); 140d409305fSDimitry Andric reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, 141d409305fSDimitry Andric reg_info->byte_size, endian::InlHostByteOrder()); 142d409305fSDimitry Andric return error; 143d409305fSDimitry Andric } 144d409305fSDimitry Andric 145d409305fSDimitry Andric Status NativeRegisterContextFreeBSD_arm64::WriteRegister( 146d409305fSDimitry Andric const RegisterInfo *reg_info, const RegisterValue ®_value) { 147d409305fSDimitry Andric Status error; 148d409305fSDimitry Andric 149d409305fSDimitry Andric if (!reg_info) 150d409305fSDimitry Andric return Status("reg_info NULL"); 151d409305fSDimitry Andric 152d409305fSDimitry Andric const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 153d409305fSDimitry Andric 154d409305fSDimitry Andric if (reg == LLDB_INVALID_REGNUM) 155d409305fSDimitry Andric return Status("no lldb regnum for %s", reg_info && reg_info->name 156d409305fSDimitry Andric ? reg_info->name 157d409305fSDimitry Andric : "<unknown register>"); 158d409305fSDimitry Andric 159d409305fSDimitry Andric uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); 160d409305fSDimitry Andric error = ReadRegisterSet(set); 161d409305fSDimitry Andric if (error.Fail()) 162d409305fSDimitry Andric return error; 163d409305fSDimitry Andric 164d409305fSDimitry Andric assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); 165d409305fSDimitry Andric ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), 166d409305fSDimitry Andric reg_info->byte_size); 167d409305fSDimitry Andric 168d409305fSDimitry Andric return WriteRegisterSet(set); 169d409305fSDimitry Andric } 170d409305fSDimitry Andric 171d409305fSDimitry Andric Status NativeRegisterContextFreeBSD_arm64::ReadAllRegisterValues( 17281ad6265SDimitry Andric lldb::WritableDataBufferSP &data_sp) { 173d409305fSDimitry Andric Status error; 174d409305fSDimitry Andric 175d409305fSDimitry Andric error = ReadRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet); 176d409305fSDimitry Andric if (error.Fail()) 177d409305fSDimitry Andric return error; 178d409305fSDimitry Andric 179d409305fSDimitry Andric error = ReadRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet); 180d409305fSDimitry Andric if (error.Fail()) 181d409305fSDimitry Andric return error; 182d409305fSDimitry Andric 183d409305fSDimitry Andric data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); 184d409305fSDimitry Andric uint8_t *dst = data_sp->GetBytes(); 185d409305fSDimitry Andric ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); 186d409305fSDimitry Andric 187d409305fSDimitry Andric return error; 188d409305fSDimitry Andric } 189d409305fSDimitry Andric 190d409305fSDimitry Andric Status NativeRegisterContextFreeBSD_arm64::WriteAllRegisterValues( 191d409305fSDimitry Andric const lldb::DataBufferSP &data_sp) { 192d409305fSDimitry Andric Status error; 193d409305fSDimitry Andric 194d409305fSDimitry Andric if (!data_sp) { 195d409305fSDimitry Andric error.SetErrorStringWithFormat( 196d409305fSDimitry Andric "NativeRegisterContextFreeBSD_arm64::%s invalid data_sp provided", 197d409305fSDimitry Andric __FUNCTION__); 198d409305fSDimitry Andric return error; 199d409305fSDimitry Andric } 200d409305fSDimitry Andric 201d409305fSDimitry Andric if (data_sp->GetByteSize() != m_reg_data.size()) { 202d409305fSDimitry Andric error.SetErrorStringWithFormat( 203d409305fSDimitry Andric "NativeRegisterContextFreeBSD_arm64::%s data_sp contained mismatched " 204d409305fSDimitry Andric "data size, expected %" PRIu64 ", actual %" PRIu64, 205d409305fSDimitry Andric __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); 206d409305fSDimitry Andric return error; 207d409305fSDimitry Andric } 208d409305fSDimitry Andric 20981ad6265SDimitry Andric const uint8_t *src = data_sp->GetBytes(); 210d409305fSDimitry Andric if (src == nullptr) { 211d409305fSDimitry Andric error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm64::%s " 212d409305fSDimitry Andric "DataBuffer::GetBytes() returned a null " 213d409305fSDimitry Andric "pointer", 214d409305fSDimitry Andric __FUNCTION__); 215d409305fSDimitry Andric return error; 216d409305fSDimitry Andric } 217d409305fSDimitry Andric ::memcpy(m_reg_data.data(), src, m_reg_data.size()); 218d409305fSDimitry Andric 219d409305fSDimitry Andric error = WriteRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet); 220d409305fSDimitry Andric if (error.Fail()) 221d409305fSDimitry Andric return error; 222d409305fSDimitry Andric 223d409305fSDimitry Andric return WriteRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet); 224d409305fSDimitry Andric } 225d409305fSDimitry Andric 226d409305fSDimitry Andric llvm::Error NativeRegisterContextFreeBSD_arm64::CopyHardwareWatchpointsFrom( 227d409305fSDimitry Andric NativeRegisterContextFreeBSD &source) { 228d409305fSDimitry Andric #ifdef LLDB_HAS_FREEBSD_WATCHPOINT 229d409305fSDimitry Andric auto &r_source = static_cast<NativeRegisterContextFreeBSD_arm64 &>(source); 230d409305fSDimitry Andric llvm::Error error = r_source.ReadHardwareDebugInfo(); 231d409305fSDimitry Andric if (error) 232d409305fSDimitry Andric return error; 233d409305fSDimitry Andric 234d409305fSDimitry Andric m_dbreg = r_source.m_dbreg; 235d409305fSDimitry Andric m_hbp_regs = r_source.m_hbp_regs; 236d409305fSDimitry Andric m_hwp_regs = r_source.m_hwp_regs; 237d409305fSDimitry Andric m_max_hbp_supported = r_source.m_max_hbp_supported; 238d409305fSDimitry Andric m_max_hwp_supported = r_source.m_max_hwp_supported; 239d409305fSDimitry Andric m_read_dbreg = true; 240d409305fSDimitry Andric 241d409305fSDimitry Andric // on FreeBSD this writes both breakpoints and watchpoints 242d409305fSDimitry Andric return WriteHardwareDebugRegs(eDREGTypeWATCH); 243d409305fSDimitry Andric #else 244d409305fSDimitry Andric return llvm::Error::success(); 245d409305fSDimitry Andric #endif 246d409305fSDimitry Andric } 247d409305fSDimitry Andric 248d409305fSDimitry Andric llvm::Error NativeRegisterContextFreeBSD_arm64::ReadHardwareDebugInfo() { 249d409305fSDimitry Andric #ifdef LLDB_HAS_FREEBSD_WATCHPOINT 25004eeddc0SDimitry Andric Log *log = GetLog(POSIXLog::Registers); 251d409305fSDimitry Andric 252d409305fSDimitry Andric // we're fully stateful, so no need to reread control registers ever 253d409305fSDimitry Andric if (m_read_dbreg) 254d409305fSDimitry Andric return llvm::Error::success(); 255d409305fSDimitry Andric 256d409305fSDimitry Andric Status res = NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS, 257d409305fSDimitry Andric m_thread.GetID(), &m_dbreg); 258d409305fSDimitry Andric if (res.Fail()) 259d409305fSDimitry Andric return res.ToError(); 260d409305fSDimitry Andric 261d409305fSDimitry Andric LLDB_LOG(log, "m_dbreg read: debug_ver={0}, nbkpts={1}, nwtpts={2}", 262d409305fSDimitry Andric m_dbreg.db_debug_ver, m_dbreg.db_nbkpts, m_dbreg.db_nwtpts); 263d409305fSDimitry Andric m_max_hbp_supported = m_dbreg.db_nbkpts; 264d409305fSDimitry Andric m_max_hwp_supported = m_dbreg.db_nwtpts; 265d409305fSDimitry Andric assert(m_max_hbp_supported <= m_hbp_regs.size()); 266d409305fSDimitry Andric assert(m_max_hwp_supported <= m_hwp_regs.size()); 267d409305fSDimitry Andric 268d409305fSDimitry Andric m_read_dbreg = true; 269d409305fSDimitry Andric return llvm::Error::success(); 270d409305fSDimitry Andric #else 271d409305fSDimitry Andric return llvm::createStringError( 272d409305fSDimitry Andric llvm::inconvertibleErrorCode(), 273d409305fSDimitry Andric "Hardware breakpoints/watchpoints require FreeBSD 14.0"); 274d409305fSDimitry Andric #endif 275d409305fSDimitry Andric } 276d409305fSDimitry Andric 277d409305fSDimitry Andric llvm::Error 278d409305fSDimitry Andric NativeRegisterContextFreeBSD_arm64::WriteHardwareDebugRegs(DREGType) { 279d409305fSDimitry Andric #ifdef LLDB_HAS_FREEBSD_WATCHPOINT 280d409305fSDimitry Andric assert(m_read_dbreg && "dbregs must be read before writing them back"); 281d409305fSDimitry Andric 282d409305fSDimitry Andric // copy data from m_*_regs to m_dbreg before writing it back 283d409305fSDimitry Andric for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 284d409305fSDimitry Andric m_dbreg.db_breakregs[i].dbr_addr = m_hbp_regs[i].address; 285d409305fSDimitry Andric m_dbreg.db_breakregs[i].dbr_ctrl = m_hbp_regs[i].control; 286d409305fSDimitry Andric } 287d409305fSDimitry Andric for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 288d409305fSDimitry Andric m_dbreg.db_watchregs[i].dbw_addr = m_hwp_regs[i].address; 289d409305fSDimitry Andric m_dbreg.db_watchregs[i].dbw_ctrl = m_hwp_regs[i].control; 290d409305fSDimitry Andric } 291d409305fSDimitry Andric 292d409305fSDimitry Andric return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(), 293d409305fSDimitry Andric &m_dbreg) 294d409305fSDimitry Andric .ToError(); 295d409305fSDimitry Andric #else 296d409305fSDimitry Andric return llvm::createStringError( 297d409305fSDimitry Andric llvm::inconvertibleErrorCode(), 298d409305fSDimitry Andric "Hardware breakpoints/watchpoints require FreeBSD 14.0"); 299d409305fSDimitry Andric #endif 300d409305fSDimitry Andric } 301d409305fSDimitry Andric 302d409305fSDimitry Andric #endif // defined (__aarch64__) 303