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