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