1 //===-- NativeRegisterContextLinux_ppc64le.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 // This implementation is related to the OpenPOWER ABI for Power Architecture 10 // 64-bit ELF V2 ABI 11 12 #if defined(__powerpc64__) 13 14 #include "NativeRegisterContextLinux_ppc64le.h" 15 16 #include "lldb/Host/common/NativeProcessProtocol.h" 17 #include "lldb/Utility/DataBufferHeap.h" 18 #include "lldb/Utility/Log.h" 19 #include "lldb/Utility/RegisterValue.h" 20 #include "lldb/Utility/Status.h" 21 22 #include "Plugins/Process/Linux/NativeProcessLinux.h" 23 #include "Plugins/Process/Linux/Procfs.h" 24 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 25 #include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" 26 27 // System includes - They have to be included after framework includes because 28 // they define some macros which collide with variable names in other modules 29 #include <sys/socket.h> 30 #include <elf.h> 31 #include <asm/ptrace.h> 32 33 #define REG_CONTEXT_SIZE \ 34 (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le)) 35 using namespace lldb; 36 using namespace lldb_private; 37 using namespace lldb_private::process_linux; 38 39 static const uint32_t g_gpr_regnums_ppc64le[] = { 40 gpr_r0_ppc64le, gpr_r1_ppc64le, gpr_r2_ppc64le, gpr_r3_ppc64le, 41 gpr_r4_ppc64le, gpr_r5_ppc64le, gpr_r6_ppc64le, gpr_r7_ppc64le, 42 gpr_r8_ppc64le, gpr_r9_ppc64le, gpr_r10_ppc64le, gpr_r11_ppc64le, 43 gpr_r12_ppc64le, gpr_r13_ppc64le, gpr_r14_ppc64le, gpr_r15_ppc64le, 44 gpr_r16_ppc64le, gpr_r17_ppc64le, gpr_r18_ppc64le, gpr_r19_ppc64le, 45 gpr_r20_ppc64le, gpr_r21_ppc64le, gpr_r22_ppc64le, gpr_r23_ppc64le, 46 gpr_r24_ppc64le, gpr_r25_ppc64le, gpr_r26_ppc64le, gpr_r27_ppc64le, 47 gpr_r28_ppc64le, gpr_r29_ppc64le, gpr_r30_ppc64le, gpr_r31_ppc64le, 48 gpr_pc_ppc64le, gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le, 49 gpr_lr_ppc64le, gpr_xer_ppc64le, gpr_cr_ppc64le, gpr_softe_ppc64le, 50 gpr_trap_ppc64le, 51 LLDB_INVALID_REGNUM // register sets need to end with this flag 52 }; 53 54 static const uint32_t g_fpr_regnums_ppc64le[] = { 55 fpr_f0_ppc64le, fpr_f1_ppc64le, fpr_f2_ppc64le, fpr_f3_ppc64le, 56 fpr_f4_ppc64le, fpr_f5_ppc64le, fpr_f6_ppc64le, fpr_f7_ppc64le, 57 fpr_f8_ppc64le, fpr_f9_ppc64le, fpr_f10_ppc64le, fpr_f11_ppc64le, 58 fpr_f12_ppc64le, fpr_f13_ppc64le, fpr_f14_ppc64le, fpr_f15_ppc64le, 59 fpr_f16_ppc64le, fpr_f17_ppc64le, fpr_f18_ppc64le, fpr_f19_ppc64le, 60 fpr_f20_ppc64le, fpr_f21_ppc64le, fpr_f22_ppc64le, fpr_f23_ppc64le, 61 fpr_f24_ppc64le, fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le, 62 fpr_f28_ppc64le, fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le, 63 fpr_fpscr_ppc64le, 64 LLDB_INVALID_REGNUM // register sets need to end with this flag 65 }; 66 67 static const uint32_t g_vmx_regnums_ppc64le[] = { 68 vmx_vr0_ppc64le, vmx_vr1_ppc64le, vmx_vr2_ppc64le, vmx_vr3_ppc64le, 69 vmx_vr4_ppc64le, vmx_vr5_ppc64le, vmx_vr6_ppc64le, vmx_vr7_ppc64le, 70 vmx_vr8_ppc64le, vmx_vr9_ppc64le, vmx_vr10_ppc64le, vmx_vr11_ppc64le, 71 vmx_vr12_ppc64le, vmx_vr13_ppc64le, vmx_vr14_ppc64le, vmx_vr15_ppc64le, 72 vmx_vr16_ppc64le, vmx_vr17_ppc64le, vmx_vr18_ppc64le, vmx_vr19_ppc64le, 73 vmx_vr20_ppc64le, vmx_vr21_ppc64le, vmx_vr22_ppc64le, vmx_vr23_ppc64le, 74 vmx_vr24_ppc64le, vmx_vr25_ppc64le, vmx_vr26_ppc64le, vmx_vr27_ppc64le, 75 vmx_vr28_ppc64le, vmx_vr29_ppc64le, vmx_vr30_ppc64le, vmx_vr31_ppc64le, 76 vmx_vscr_ppc64le, vmx_vrsave_ppc64le, 77 LLDB_INVALID_REGNUM // register sets need to end with this flag 78 }; 79 80 static const uint32_t g_vsx_regnums_ppc64le[] = { 81 vsx_vs0_ppc64le, vsx_vs1_ppc64le, vsx_vs2_ppc64le, vsx_vs3_ppc64le, 82 vsx_vs4_ppc64le, vsx_vs5_ppc64le, vsx_vs6_ppc64le, vsx_vs7_ppc64le, 83 vsx_vs8_ppc64le, vsx_vs9_ppc64le, vsx_vs10_ppc64le, vsx_vs11_ppc64le, 84 vsx_vs12_ppc64le, vsx_vs13_ppc64le, vsx_vs14_ppc64le, vsx_vs15_ppc64le, 85 vsx_vs16_ppc64le, vsx_vs17_ppc64le, vsx_vs18_ppc64le, vsx_vs19_ppc64le, 86 vsx_vs20_ppc64le, vsx_vs21_ppc64le, vsx_vs22_ppc64le, vsx_vs23_ppc64le, 87 vsx_vs24_ppc64le, vsx_vs25_ppc64le, vsx_vs26_ppc64le, vsx_vs27_ppc64le, 88 vsx_vs28_ppc64le, vsx_vs29_ppc64le, vsx_vs30_ppc64le, vsx_vs31_ppc64le, 89 vsx_vs32_ppc64le, vsx_vs33_ppc64le, vsx_vs34_ppc64le, vsx_vs35_ppc64le, 90 vsx_vs36_ppc64le, vsx_vs37_ppc64le, vsx_vs38_ppc64le, vsx_vs39_ppc64le, 91 vsx_vs40_ppc64le, vsx_vs41_ppc64le, vsx_vs42_ppc64le, vsx_vs43_ppc64le, 92 vsx_vs44_ppc64le, vsx_vs45_ppc64le, vsx_vs46_ppc64le, vsx_vs47_ppc64le, 93 vsx_vs48_ppc64le, vsx_vs49_ppc64le, vsx_vs50_ppc64le, vsx_vs51_ppc64le, 94 vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le, 95 vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le, 96 vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le, 97 LLDB_INVALID_REGNUM // register sets need to end with this flag 98 }; 99 100 // Number of register sets provided by this context. 101 static constexpr int k_num_register_sets = 4; 102 103 static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = { 104 {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le, 105 g_gpr_regnums_ppc64le}, 106 {"Floating Point Registers", "fpr", k_num_fpr_registers_ppc64le, 107 g_fpr_regnums_ppc64le}, 108 {"AltiVec/VMX Registers", "vmx", k_num_vmx_registers_ppc64le, 109 g_vmx_regnums_ppc64le}, 110 {"VSX Registers", "vsx", k_num_vsx_registers_ppc64le, 111 g_vsx_regnums_ppc64le}, 112 }; 113 114 std::unique_ptr<NativeRegisterContextLinux> 115 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 116 const ArchSpec &target_arch, NativeThreadLinux &native_thread) { 117 switch (target_arch.GetMachine()) { 118 case llvm::Triple::ppc64le: 119 return std::make_unique<NativeRegisterContextLinux_ppc64le>(target_arch, 120 native_thread); 121 default: 122 llvm_unreachable("have no register context for architecture"); 123 } 124 } 125 126 NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le( 127 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 128 : NativeRegisterContextRegisterInfo( 129 native_thread, new RegisterInfoPOSIX_ppc64le(target_arch)), 130 NativeRegisterContextLinux(native_thread) { 131 if (target_arch.GetMachine() != llvm::Triple::ppc64le) { 132 llvm_unreachable("Unhandled target architecture."); 133 } 134 135 ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le)); 136 ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le)); 137 ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le)); 138 ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le)); 139 ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); 140 } 141 142 uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount() const { 143 return k_num_register_sets; 144 } 145 146 const RegisterSet * 147 NativeRegisterContextLinux_ppc64le::GetRegisterSet(uint32_t set_index) const { 148 if (set_index < k_num_register_sets) 149 return &g_reg_sets_ppc64le[set_index]; 150 151 return nullptr; 152 } 153 154 uint32_t NativeRegisterContextLinux_ppc64le::GetUserRegisterCount() const { 155 uint32_t count = 0; 156 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) 157 count += g_reg_sets_ppc64le[set_index].num_registers; 158 return count; 159 } 160 161 Status NativeRegisterContextLinux_ppc64le::ReadRegister( 162 const RegisterInfo *reg_info, RegisterValue ®_value) { 163 Status error; 164 165 if (!reg_info) { 166 error.SetErrorString("reg_info NULL"); 167 return error; 168 } 169 170 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 171 172 if (IsFPR(reg)) { 173 error = ReadFPR(); 174 if (error.Fail()) 175 return error; 176 177 // Get pointer to m_fpr_ppc64le variable and set the data from it. 178 uint32_t fpr_offset = CalculateFprOffset(reg_info); 179 assert(fpr_offset < sizeof m_fpr_ppc64le); 180 uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset; 181 reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, 182 eByteOrderLittle, error); 183 } else if (IsVSX(reg)) { 184 uint32_t vsx_offset = CalculateVsxOffset(reg_info); 185 assert(vsx_offset < sizeof(m_vsx_ppc64le)); 186 187 if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { 188 error = ReadVSX(); 189 if (error.Fail()) 190 return error; 191 192 error = ReadFPR(); 193 if (error.Fail()) 194 return error; 195 196 uint64_t value[2]; 197 uint8_t *dst, *src; 198 dst = (uint8_t *)&value; 199 src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; 200 ::memcpy(dst, src, 8); 201 dst += 8; 202 src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; 203 ::memcpy(dst, src, 8); 204 reg_value.SetFromMemoryData(reg_info, &value, reg_info->byte_size, 205 eByteOrderLittle, error); 206 } else { 207 error = ReadVMX(); 208 if (error.Fail()) 209 return error; 210 211 // Get pointer to m_vmx_ppc64le variable and set the data from it. 212 uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; 213 uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; 214 reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, 215 eByteOrderLittle, error); 216 } 217 } else if (IsVMX(reg)) { 218 error = ReadVMX(); 219 if (error.Fail()) 220 return error; 221 222 // Get pointer to m_vmx_ppc64le variable and set the data from it. 223 uint32_t vmx_offset = CalculateVmxOffset(reg_info); 224 assert(vmx_offset < sizeof m_vmx_ppc64le); 225 uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; 226 reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, 227 eByteOrderLittle, error); 228 } else if (IsGPR(reg)) { 229 error = ReadGPR(); 230 if (error.Fail()) 231 return error; 232 233 uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset; 234 reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, 235 eByteOrderLittle, error); 236 } else { 237 return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " 238 "or VMX, read strategy unknown"); 239 } 240 241 return error; 242 } 243 244 Status NativeRegisterContextLinux_ppc64le::WriteRegister( 245 const RegisterInfo *reg_info, const RegisterValue ®_value) { 246 Status error; 247 if (!reg_info) 248 return Status("reg_info NULL"); 249 250 const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 251 if (reg_index == LLDB_INVALID_REGNUM) 252 return Status("no lldb regnum for %s", reg_info && reg_info->name 253 ? reg_info->name 254 : "<unknown register>"); 255 256 if (IsGPR(reg_index)) { 257 error = ReadGPR(); 258 if (error.Fail()) 259 return error; 260 261 uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset; 262 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); 263 264 error = WriteGPR(); 265 if (error.Fail()) 266 return error; 267 268 return Status(); 269 } 270 271 if (IsFPR(reg_index)) { 272 error = ReadFPR(); 273 if (error.Fail()) 274 return error; 275 276 // Get pointer to m_fpr_ppc64le variable and set the data to it. 277 uint32_t fpr_offset = CalculateFprOffset(reg_info); 278 assert(fpr_offset < GetFPRSize()); 279 uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset; 280 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); 281 282 error = WriteFPR(); 283 if (error.Fail()) 284 return error; 285 286 return Status(); 287 } 288 289 if (IsVMX(reg_index)) { 290 error = ReadVMX(); 291 if (error.Fail()) 292 return error; 293 294 // Get pointer to m_vmx_ppc64le variable and set the data to it. 295 uint32_t vmx_offset = CalculateVmxOffset(reg_info); 296 assert(vmx_offset < sizeof(m_vmx_ppc64le)); 297 uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; 298 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); 299 300 error = WriteVMX(); 301 if (error.Fail()) 302 return error; 303 304 return Status(); 305 } 306 307 if (IsVSX(reg_index)) { 308 uint32_t vsx_offset = CalculateVsxOffset(reg_info); 309 assert(vsx_offset < sizeof(m_vsx_ppc64le)); 310 311 if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { 312 error = ReadVSX(); 313 if (error.Fail()) 314 return error; 315 316 error = ReadFPR(); 317 if (error.Fail()) 318 return error; 319 320 uint64_t value[2]; 321 ::memcpy(value, reg_value.GetBytes(), 16); 322 uint8_t *dst, *src; 323 src = (uint8_t *)value; 324 dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; 325 ::memcpy(dst, src, 8); 326 src += 8; 327 dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; 328 ::memcpy(dst, src, 8); 329 330 WriteVSX(); 331 WriteFPR(); 332 } else { 333 error = ReadVMX(); 334 if (error.Fail()) 335 return error; 336 337 // Get pointer to m_vmx_ppc64le variable and set the data from it. 338 uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; 339 uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; 340 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); 341 WriteVMX(); 342 } 343 344 return Status(); 345 } 346 347 return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " 348 "or VMX, write strategy unknown"); 349 } 350 351 Status NativeRegisterContextLinux_ppc64le::ReadAllRegisterValues( 352 lldb::WritableDataBufferSP &data_sp) { 353 Status error; 354 355 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 356 error = ReadGPR(); 357 if (error.Fail()) 358 return error; 359 360 error = ReadFPR(); 361 if (error.Fail()) 362 return error; 363 364 error = ReadVMX(); 365 if (error.Fail()) 366 return error; 367 368 error = ReadVSX(); 369 if (error.Fail()) 370 return error; 371 372 uint8_t *dst = data_sp->GetBytes(); 373 ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize()); 374 dst += GetGPRSize(); 375 ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize()); 376 dst += GetFPRSize(); 377 ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le)); 378 dst += sizeof(m_vmx_ppc64le); 379 ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le)); 380 381 return error; 382 } 383 384 Status NativeRegisterContextLinux_ppc64le::WriteAllRegisterValues( 385 const lldb::DataBufferSP &data_sp) { 386 Status error; 387 388 if (!data_sp) { 389 error.SetErrorStringWithFormat( 390 "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided", 391 __FUNCTION__); 392 return error; 393 } 394 395 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 396 error.SetErrorStringWithFormat( 397 "NativeRegisterContextLinux_ppc64le::%s data_sp contained mismatched " 398 "data size, expected %" PRIu64 ", actual %" PRIu64, 399 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 400 return error; 401 } 402 403 const uint8_t *src = data_sp->GetBytes(); 404 if (src == nullptr) { 405 error.SetErrorStringWithFormat("NativeRegisterContextLinux_ppc64le::%s " 406 "DataBuffer::GetBytes() returned a null " 407 "pointer", 408 __FUNCTION__); 409 return error; 410 } 411 412 ::memcpy(&m_gpr_ppc64le, src, GetGPRSize()); 413 error = WriteGPR(); 414 415 if (error.Fail()) 416 return error; 417 418 src += GetGPRSize(); 419 ::memcpy(&m_fpr_ppc64le, src, GetFPRSize()); 420 421 error = WriteFPR(); 422 if (error.Fail()) 423 return error; 424 425 src += GetFPRSize(); 426 ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le)); 427 428 error = WriteVMX(); 429 if (error.Fail()) 430 return error; 431 432 src += sizeof(m_vmx_ppc64le); 433 ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le)); 434 error = WriteVSX(); 435 436 return error; 437 } 438 439 bool NativeRegisterContextLinux_ppc64le::IsGPR(unsigned reg) const { 440 return reg <= k_last_gpr_ppc64le; // GPR's come first. 441 } 442 443 bool NativeRegisterContextLinux_ppc64le::IsFPR(unsigned reg) const { 444 return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le); 445 } 446 447 uint32_t NativeRegisterContextLinux_ppc64le::CalculateFprOffset( 448 const RegisterInfo *reg_info) const { 449 return reg_info->byte_offset - 450 GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset; 451 } 452 453 uint32_t NativeRegisterContextLinux_ppc64le::CalculateVmxOffset( 454 const RegisterInfo *reg_info) const { 455 return reg_info->byte_offset - 456 GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset; 457 } 458 459 uint32_t NativeRegisterContextLinux_ppc64le::CalculateVsxOffset( 460 const RegisterInfo *reg_info) const { 461 return reg_info->byte_offset - 462 GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset; 463 } 464 465 Status NativeRegisterContextLinux_ppc64le::ReadVMX() { 466 int regset = NT_PPC_VMX; 467 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(), 468 ®set, &m_vmx_ppc64le, 469 sizeof(m_vmx_ppc64le)); 470 } 471 472 Status NativeRegisterContextLinux_ppc64le::WriteVMX() { 473 int regset = NT_PPC_VMX; 474 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVRREGS, m_thread.GetID(), 475 ®set, &m_vmx_ppc64le, 476 sizeof(m_vmx_ppc64le)); 477 } 478 479 Status NativeRegisterContextLinux_ppc64le::ReadVSX() { 480 int regset = NT_PPC_VSX; 481 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(), 482 ®set, &m_vsx_ppc64le, 483 sizeof(m_vsx_ppc64le)); 484 } 485 486 Status NativeRegisterContextLinux_ppc64le::WriteVSX() { 487 int regset = NT_PPC_VSX; 488 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVSRREGS, m_thread.GetID(), 489 ®set, &m_vsx_ppc64le, 490 sizeof(m_vsx_ppc64le)); 491 } 492 493 bool NativeRegisterContextLinux_ppc64le::IsVMX(unsigned reg) { 494 return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le); 495 } 496 497 bool NativeRegisterContextLinux_ppc64le::IsVSX(unsigned reg) { 498 return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le); 499 } 500 501 uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints() { 502 Log *log = GetLog(POSIXLog::Watchpoints); 503 504 // Read hardware breakpoint and watchpoint information. 505 Status error = ReadHardwareDebugInfo(); 506 507 if (error.Fail()) 508 return 0; 509 510 LLDB_LOG(log, "{0}", m_max_hwp_supported); 511 return m_max_hwp_supported; 512 } 513 514 uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint( 515 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 516 Log *log = GetLog(POSIXLog::Watchpoints); 517 LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, 518 watch_flags); 519 520 // Read hardware breakpoint and watchpoint information. 521 Status error = ReadHardwareDebugInfo(); 522 523 if (error.Fail()) 524 return LLDB_INVALID_INDEX32; 525 526 uint32_t control_value = 0, wp_index = 0; 527 lldb::addr_t real_addr = addr; 528 uint32_t rw_mode = 0; 529 530 // Check if we are setting watchpoint other than read/write/access Update 531 // watchpoint flag to match ppc64le write-read bit configuration. 532 switch (watch_flags) { 533 case eWatchpointKindWrite: 534 rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE; 535 watch_flags = 2; 536 break; 537 case eWatchpointKindRead: 538 rw_mode = PPC_BREAKPOINT_TRIGGER_READ; 539 watch_flags = 1; 540 break; 541 case (eWatchpointKindRead | eWatchpointKindWrite): 542 rw_mode = PPC_BREAKPOINT_TRIGGER_RW; 543 break; 544 default: 545 return LLDB_INVALID_INDEX32; 546 } 547 548 // Check if size has a valid hardware watchpoint length. 549 if (size != 1 && size != 2 && size != 4 && size != 8) 550 return LLDB_INVALID_INDEX32; 551 552 // Check 8-byte alignment for hardware watchpoint target address. Below is a 553 // hack to recalculate address and size in order to make sure we can watch 554 // non 8-byte aligned addresses as well. 555 if (addr & 0x07) { 556 557 addr_t begin = llvm::alignDown(addr, 8); 558 addr_t end = llvm::alignTo(addr + size, 8); 559 size = llvm::PowerOf2Ceil(end - begin); 560 561 addr = addr & (~0x07); 562 } 563 564 // Setup control value 565 control_value = watch_flags << 3; 566 control_value |= ((1 << size) - 1) << 5; 567 control_value |= (2 << 1) | 1; 568 569 // Iterate over stored watchpoints and find a free wp_index 570 wp_index = LLDB_INVALID_INDEX32; 571 for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 572 if ((m_hwp_regs[i].control & 1) == 0) { 573 wp_index = i; // Mark last free slot 574 } else if (m_hwp_regs[i].address == addr) { 575 return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. 576 } 577 } 578 579 if (wp_index == LLDB_INVALID_INDEX32) 580 return LLDB_INVALID_INDEX32; 581 582 // Update watchpoint in local cache 583 m_hwp_regs[wp_index].real_addr = real_addr; 584 m_hwp_regs[wp_index].address = addr; 585 m_hwp_regs[wp_index].control = control_value; 586 m_hwp_regs[wp_index].mode = rw_mode; 587 588 // PTRACE call to set corresponding watchpoint register. 589 error = WriteHardwareDebugRegs(); 590 591 if (error.Fail()) { 592 m_hwp_regs[wp_index].address = 0; 593 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1); 594 595 return LLDB_INVALID_INDEX32; 596 } 597 598 return wp_index; 599 } 600 601 bool NativeRegisterContextLinux_ppc64le::ClearHardwareWatchpoint( 602 uint32_t wp_index) { 603 Log *log = GetLog(POSIXLog::Watchpoints); 604 LLDB_LOG(log, "wp_index: {0}", wp_index); 605 606 // Read hardware breakpoint and watchpoint information. 607 Status error = ReadHardwareDebugInfo(); 608 609 if (error.Fail()) 610 return false; 611 612 if (wp_index >= m_max_hwp_supported) 613 return false; 614 615 // Create a backup we can revert to in case of failure. 616 lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 617 uint32_t tempControl = m_hwp_regs[wp_index].control; 618 long *tempSlot = reinterpret_cast<long *>(m_hwp_regs[wp_index].slot); 619 620 // Update watchpoint in local cache 621 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1); 622 m_hwp_regs[wp_index].address = 0; 623 m_hwp_regs[wp_index].slot = 0; 624 m_hwp_regs[wp_index].mode = 0; 625 626 // Ptrace call to update hardware debug registers 627 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_DELHWDEBUG, 628 m_thread.GetID(), 0, tempSlot); 629 630 if (error.Fail()) { 631 m_hwp_regs[wp_index].control = tempControl; 632 m_hwp_regs[wp_index].address = tempAddr; 633 m_hwp_regs[wp_index].slot = reinterpret_cast<long>(tempSlot); 634 635 return false; 636 } 637 638 return true; 639 } 640 641 uint32_t 642 NativeRegisterContextLinux_ppc64le::GetWatchpointSize(uint32_t wp_index) { 643 Log *log = GetLog(POSIXLog::Watchpoints); 644 LLDB_LOG(log, "wp_index: {0}", wp_index); 645 646 unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff; 647 if (llvm::isPowerOf2_32(control + 1)) { 648 return llvm::countPopulation(control); 649 } 650 651 return 0; 652 } 653 654 bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled( 655 uint32_t wp_index) { 656 Log *log = GetLog(POSIXLog::Watchpoints); 657 LLDB_LOG(log, "wp_index: {0}", wp_index); 658 659 return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1); 660 } 661 662 Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex( 663 uint32_t &wp_index, lldb::addr_t trap_addr) { 664 Log *log = GetLog(POSIXLog::Watchpoints); 665 LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); 666 667 uint32_t watch_size; 668 lldb::addr_t watch_addr; 669 670 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { 671 watch_size = GetWatchpointSize(wp_index); 672 watch_addr = m_hwp_regs[wp_index].address; 673 674 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && 675 trap_addr <= watch_addr + watch_size) { 676 m_hwp_regs[wp_index].hit_addr = trap_addr; 677 return Status(); 678 } 679 } 680 681 wp_index = LLDB_INVALID_INDEX32; 682 return Status(); 683 } 684 685 lldb::addr_t 686 NativeRegisterContextLinux_ppc64le::GetWatchpointAddress(uint32_t wp_index) { 687 Log *log = GetLog(POSIXLog::Watchpoints); 688 LLDB_LOG(log, "wp_index: {0}", wp_index); 689 690 if (wp_index >= m_max_hwp_supported) 691 return LLDB_INVALID_ADDRESS; 692 693 if (WatchpointIsEnabled(wp_index)) 694 return m_hwp_regs[wp_index].real_addr; 695 else 696 return LLDB_INVALID_ADDRESS; 697 } 698 699 lldb::addr_t 700 NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress(uint32_t wp_index) { 701 Log *log = GetLog(POSIXLog::Watchpoints); 702 LLDB_LOG(log, "wp_index: {0}", wp_index); 703 704 if (wp_index >= m_max_hwp_supported) 705 return LLDB_INVALID_ADDRESS; 706 707 if (WatchpointIsEnabled(wp_index)) 708 return m_hwp_regs[wp_index].hit_addr; 709 710 return LLDB_INVALID_ADDRESS; 711 } 712 713 Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo() { 714 if (!m_refresh_hwdebug_info) { 715 return Status(); 716 } 717 718 ::pid_t tid = m_thread.GetID(); 719 720 struct ppc_debug_info hwdebug_info; 721 Status error; 722 723 error = NativeProcessLinux::PtraceWrapper( 724 PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info, sizeof(hwdebug_info)); 725 726 if (error.Fail()) 727 return error; 728 729 m_max_hwp_supported = hwdebug_info.num_data_bps; 730 m_max_hbp_supported = hwdebug_info.num_instruction_bps; 731 m_refresh_hwdebug_info = false; 732 733 return error; 734 } 735 736 Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs() { 737 struct ppc_hw_breakpoint reg_state; 738 Status error; 739 long ret; 740 741 for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 742 reg_state.addr = m_hwp_regs[i].address; 743 reg_state.trigger_type = m_hwp_regs[i].mode; 744 reg_state.version = 1; 745 reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT; 746 reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; 747 reg_state.addr2 = 0; 748 reg_state.condition_value = 0; 749 750 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_SETHWDEBUG, 751 m_thread.GetID(), 0, ®_state, 752 sizeof(reg_state), &ret); 753 754 if (error.Fail()) 755 return error; 756 757 m_hwp_regs[i].slot = ret; 758 } 759 760 return error; 761 } 762 763 #endif // defined(__powerpc64__) 764