12#if defined(__powerpc64__)
30#include <sys/socket.h>
32#include <asm/ptrace.h>
34#define REG_CONTEXT_SIZE \
35 (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le))
40static const uint32_t g_gpr_regnums_ppc64le[] = {
55static const uint32_t g_fpr_regnums_ppc64le[] = {
68static const uint32_t g_vmx_regnums_ppc64le[] = {
81static const uint32_t g_vsx_regnums_ppc64le[] = {
106 g_gpr_regnums_ppc64le},
108 g_fpr_regnums_ppc64le},
110 g_vmx_regnums_ppc64le},
112 g_vsx_regnums_ppc64le},
115std::unique_ptr<NativeRegisterContextLinux>
116NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
119 case llvm::Triple::ppc64le:
120 return std::make_unique<NativeRegisterContextLinux_ppc64le>(target_arch,
123 llvm_unreachable(
"have no register context for architecture");
127llvm::Expected<ArchSpec>
128NativeRegisterContextLinux::DetermineArchitecture(
lldb::tid_t tid) {
129 return HostInfo::GetArchitecture();
132NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le(
137 if (target_arch.
GetMachine() != llvm::Triple::ppc64le) {
138 llvm_unreachable(
"Unhandled target architecture.");
141 ::memset(&m_gpr_ppc64le, 0,
sizeof(m_gpr_ppc64le));
142 ::memset(&m_fpr_ppc64le, 0,
sizeof(m_fpr_ppc64le));
143 ::memset(&m_vmx_ppc64le, 0,
sizeof(m_vmx_ppc64le));
144 ::memset(&m_vsx_ppc64le, 0,
sizeof(m_vsx_ppc64le));
145 ::memset(&m_hwp_regs, 0,
sizeof(m_hwp_regs));
148uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount()
const {
153NativeRegisterContextLinux_ppc64le::GetRegisterSet(uint32_t set_index)
const {
160uint32_t NativeRegisterContextLinux_ppc64le::GetUserRegisterCount()
const {
167Status NativeRegisterContextLinux_ppc64le::ReadRegister(
172 error = Status::FromErrorString(
"reg_info NULL");
184 uint32_t fpr_offset = CalculateFprOffset(reg_info);
185 assert(fpr_offset <
sizeof m_fpr_ppc64le);
186 uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
188 eByteOrderLittle,
error);
189 }
else if (IsVSX(reg)) {
190 uint32_t vsx_offset = CalculateVsxOffset(reg_info);
191 assert(vsx_offset <
sizeof(m_vsx_ppc64le));
193 if (vsx_offset <
sizeof(m_vsx_ppc64le) / 2) {
204 dst = (uint8_t *)&value;
205 src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
206 ::memcpy(dst, src, 8);
208 src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
209 ::memcpy(dst, src, 8);
211 eByteOrderLittle,
error);
218 uint32_t vmx_offset = vsx_offset -
sizeof(m_vsx_ppc64le) / 2;
219 uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
221 eByteOrderLittle,
error);
223 }
else if (IsVMX(reg)) {
229 uint32_t vmx_offset = CalculateVmxOffset(reg_info);
230 assert(vmx_offset <
sizeof m_vmx_ppc64le);
231 uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
233 eByteOrderLittle,
error);
234 }
else if (IsGPR(reg)) {
239 uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->
byte_offset;
241 eByteOrderLittle,
error);
243 return Status::FromErrorString(
244 "failed - register wasn't recognized to be a GPR, FPR, VSX "
245 "or VMX, read strategy unknown");
251Status NativeRegisterContextLinux_ppc64le::WriteRegister(
255 return Status::FromErrorString(
"reg_info NULL");
259 return Status::FromErrorStringWithFormat(
260 "no lldb regnum for %s",
261 reg_info && reg_info->
name ? reg_info->
name :
"<unknown register>");
263 if (IsGPR(reg_index)) {
268 uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->
byte_offset;
278 if (IsFPR(reg_index)) {
284 uint32_t fpr_offset = CalculateFprOffset(reg_info);
285 assert(fpr_offset < GetFPRSize());
286 uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
296 if (IsVMX(reg_index)) {
302 uint32_t vmx_offset = CalculateVmxOffset(reg_info);
303 assert(vmx_offset <
sizeof(m_vmx_ppc64le));
304 uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
314 if (IsVSX(reg_index)) {
315 uint32_t vsx_offset = CalculateVsxOffset(reg_info);
316 assert(vsx_offset <
sizeof(m_vsx_ppc64le));
318 if (vsx_offset <
sizeof(m_vsx_ppc64le) / 2) {
328 ::memcpy(value, reg_value.
GetBytes(), 16);
330 src = (uint8_t *)value;
331 dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
332 ::memcpy(dst, src, 8);
334 dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
335 ::memcpy(dst, src, 8);
345 uint32_t vmx_offset = vsx_offset -
sizeof(m_vsx_ppc64le) / 2;
346 uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
354 return Status::FromErrorString(
355 "failed - register wasn't recognized to be a GPR, FPR, VSX "
356 "or VMX, write strategy unknown");
359Status NativeRegisterContextLinux_ppc64le::ReadAllRegisterValues(
380 uint8_t *dst = data_sp->GetBytes();
381 ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize());
383 ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize());
385 ::memcpy(dst, &m_vmx_ppc64le,
sizeof(m_vmx_ppc64le));
386 dst +=
sizeof(m_vmx_ppc64le);
387 ::memcpy(dst, &m_vsx_ppc64le,
sizeof(m_vsx_ppc64le));
392Status NativeRegisterContextLinux_ppc64le::WriteAllRegisterValues(
397 error = Status::FromErrorStringWithFormat(
398 "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided",
404 error = Status::FromErrorStringWithFormat(
405 "NativeRegisterContextLinux_ppc64le::%s data_sp contained mismatched "
406 "data size, expected %" PRIu64
", actual %" PRIu64,
411 const uint8_t *src = data_sp->GetBytes();
412 if (src ==
nullptr) {
413 error = Status::FromErrorStringWithFormat(
414 "NativeRegisterContextLinux_ppc64le::%s "
415 "DataBuffer::GetBytes() returned a null "
421 ::memcpy(&m_gpr_ppc64le, src, GetGPRSize());
428 ::memcpy(&m_fpr_ppc64le, src, GetFPRSize());
435 ::memcpy(&m_vmx_ppc64le, src,
sizeof(m_vmx_ppc64le));
441 src +=
sizeof(m_vmx_ppc64le);
442 ::memcpy(&m_vsx_ppc64le, src,
sizeof(m_vsx_ppc64le));
448bool NativeRegisterContextLinux_ppc64le::IsGPR(
unsigned reg)
const {
452bool NativeRegisterContextLinux_ppc64le::IsFPR(
unsigned reg)
const {
456uint32_t NativeRegisterContextLinux_ppc64le::CalculateFprOffset(
462uint32_t NativeRegisterContextLinux_ppc64le::CalculateVmxOffset(
468uint32_t NativeRegisterContextLinux_ppc64le::CalculateVsxOffset(
474Status NativeRegisterContextLinux_ppc64le::ReadVMX() {
475 int regset = NT_PPC_VMX;
476 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(),
477 ®set, &m_vmx_ppc64le,
478 sizeof(m_vmx_ppc64le));
481Status NativeRegisterContextLinux_ppc64le::WriteVMX() {
482 int regset = NT_PPC_VMX;
483 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVRREGS, m_thread.GetID(),
484 ®set, &m_vmx_ppc64le,
485 sizeof(m_vmx_ppc64le));
488Status NativeRegisterContextLinux_ppc64le::ReadVSX() {
489 int regset = NT_PPC_VSX;
490 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(),
491 ®set, &m_vsx_ppc64le,
492 sizeof(m_vsx_ppc64le));
495Status NativeRegisterContextLinux_ppc64le::WriteVSX() {
496 int regset = NT_PPC_VSX;
497 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVSRREGS, m_thread.GetID(),
498 ®set, &m_vsx_ppc64le,
499 sizeof(m_vsx_ppc64le));
502bool NativeRegisterContextLinux_ppc64le::IsVMX(
unsigned reg) {
506bool NativeRegisterContextLinux_ppc64le::IsVSX(
unsigned reg) {
510uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints() {
511 Log *log =
GetLog(POSIXLog::Watchpoints);
519 LLDB_LOG(log,
"{0}", m_max_hwp_supported);
520 return m_max_hwp_supported;
523uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint(
525 Log *log =
GetLog(POSIXLog::Watchpoints);
526 LLDB_LOG(log,
"addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
535 uint32_t control_value = 0, wp_index = 0;
537 uint32_t rw_mode = 0;
541 switch (watch_flags) {
542 case eWatchpointKindWrite:
543 rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE;
546 case eWatchpointKindRead:
547 rw_mode = PPC_BREAKPOINT_TRIGGER_READ;
550 case (eWatchpointKindRead | eWatchpointKindWrite):
551 rw_mode = PPC_BREAKPOINT_TRIGGER_RW;
558 if (size != 1 && size != 2 && size != 4 && size != 8)
566 addr_t begin = llvm::alignDown(addr, 8);
567 addr_t end = llvm::alignTo(addr + size, 8);
568 size = llvm::PowerOf2Ceil(end - begin);
570 addr = addr & (~0x07);
574 control_value = watch_flags << 3;
575 control_value |= ((1 << size) - 1) << 5;
576 control_value |= (2 << 1) | 1;
580 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
581 if ((m_hwp_regs[i].control & 1) == 0) {
583 }
else if (m_hwp_regs[i].address == addr) {
592 m_hwp_regs[wp_index].real_addr = real_addr;
593 m_hwp_regs[wp_index].address = addr;
594 m_hwp_regs[wp_index].control = control_value;
595 m_hwp_regs[wp_index].mode = rw_mode;
598 error = WriteHardwareDebugRegs();
601 m_hwp_regs[wp_index].address = 0;
602 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
610bool NativeRegisterContextLinux_ppc64le::ClearHardwareWatchpoint(
612 Log *log =
GetLog(POSIXLog::Watchpoints);
613 LLDB_LOG(log,
"wp_index: {0}", wp_index);
621 if (wp_index >= m_max_hwp_supported)
626 uint32_t tempControl = m_hwp_regs[wp_index].control;
627 long *tempSlot =
reinterpret_cast<long *
>(m_hwp_regs[wp_index].slot);
630 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
631 m_hwp_regs[wp_index].address = 0;
632 m_hwp_regs[wp_index].slot = 0;
633 m_hwp_regs[wp_index].mode = 0;
636 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_DELHWDEBUG,
637 m_thread.GetID(), 0, tempSlot);
640 m_hwp_regs[wp_index].control = tempControl;
641 m_hwp_regs[wp_index].address = tempAddr;
642 m_hwp_regs[wp_index].slot =
reinterpret_cast<long>(tempSlot);
651NativeRegisterContextLinux_ppc64le::GetWatchpointSize(uint32_t wp_index) {
652 Log *log =
GetLog(POSIXLog::Watchpoints);
653 LLDB_LOG(log,
"wp_index: {0}", wp_index);
655 unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff;
656 if (llvm::isPowerOf2_32(control + 1)) {
657 return llvm::popcount(control);
663bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled(
665 Log *log =
GetLog(POSIXLog::Watchpoints);
666 LLDB_LOG(log,
"wp_index: {0}", wp_index);
668 return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1);
671Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex(
673 Log *log =
GetLog(POSIXLog::Watchpoints);
674 LLDB_LOG(log,
"wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
679 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
680 watch_size = GetWatchpointSize(wp_index);
681 watch_addr = m_hwp_regs[wp_index].address;
683 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
684 trap_addr <= watch_addr + watch_size) {
685 m_hwp_regs[wp_index].hit_addr = trap_addr;
695NativeRegisterContextLinux_ppc64le::GetWatchpointAddress(uint32_t wp_index) {
696 Log *log =
GetLog(POSIXLog::Watchpoints);
697 LLDB_LOG(log,
"wp_index: {0}", wp_index);
699 if (wp_index >= m_max_hwp_supported)
702 if (WatchpointIsEnabled(wp_index))
703 return m_hwp_regs[wp_index].real_addr;
709NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress(uint32_t wp_index) {
710 Log *log =
GetLog(POSIXLog::Watchpoints);
711 LLDB_LOG(log,
"wp_index: {0}", wp_index);
713 if (wp_index >= m_max_hwp_supported)
716 if (WatchpointIsEnabled(wp_index))
717 return m_hwp_regs[wp_index].hit_addr;
722Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo() {
723 if (!m_refresh_hwdebug_info) {
727 ::pid_t tid = m_thread.GetID();
729 struct ppc_debug_info hwdebug_info;
732 error = NativeProcessLinux::PtraceWrapper(
733 PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info,
sizeof(hwdebug_info));
738 m_max_hwp_supported = hwdebug_info.num_data_bps;
739 m_max_hbp_supported = hwdebug_info.num_instruction_bps;
740 m_refresh_hwdebug_info =
false;
745Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs() {
746 struct ppc_hw_breakpoint reg_state;
750 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
751 reg_state.addr = m_hwp_regs[i].address;
752 reg_state.trigger_type = m_hwp_regs[i].mode;
753 reg_state.version = 1;
754 reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
755 reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
757 reg_state.condition_value = 0;
759 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_SETHWDEBUG,
760 m_thread.GetID(), 0, ®_state,
761 sizeof(reg_state), &ret);
766 m_hwp_regs[i].slot = ret;
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
constexpr size_t k_num_register_sets
static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets]
An architecture specification class.
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
A subclass of DataBuffer that stores a data buffer on the heap.
uint32_t SetFromMemoryData(const RegisterInfo ®_info, const void *src, uint32_t src_len, lldb::ByteOrder src_byte_order, Status &error)
const void * GetBytes() const
uint32_t GetByteSize() const
#define LLDB_INVALID_INDEX32
#define LLDB_INVALID_ADDRESS
#define LLDB_INVALID_REGNUM
@ k_num_gpr_registers_ppc64le
@ k_num_vsx_registers_ppc64le
@ k_num_vmx_registers_ppc64le
@ k_num_fpr_registers_ppc64le
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
@ eRegisterKindLLDB
lldb's internal register numbers
Every register is described in detail including its name, alternate name (optional),...
uint32_t byte_offset
The byte offset in the register context data where this register's value is found.
uint32_t byte_size
Size in bytes of the register.
uint32_t kinds[lldb::kNumRegisterKinds]
Holds all of the various register numbers for all register kinds.
const char * name
Name of this register, can't be NULL.
Registers are grouped into register sets.