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