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