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.SetErrorString(
"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(
"failed - register wasn't recognized to be a GPR, FPR, VSX "
244 "or VMX, read strategy unknown");
250Status NativeRegisterContextLinux_ppc64le::WriteRegister(
254 return Status(
"reg_info NULL");
258 return Status(
"no lldb regnum for %s", reg_info && reg_info->
name
260 :
"<unknown register>");
262 if (IsGPR(reg_index)) {
267 uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->
byte_offset;
277 if (IsFPR(reg_index)) {
283 uint32_t fpr_offset = CalculateFprOffset(reg_info);
284 assert(fpr_offset < GetFPRSize());
285 uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
295 if (IsVMX(reg_index)) {
301 uint32_t vmx_offset = CalculateVmxOffset(reg_info);
302 assert(vmx_offset <
sizeof(m_vmx_ppc64le));
303 uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
313 if (IsVSX(reg_index)) {
314 uint32_t vsx_offset = CalculateVsxOffset(reg_info);
315 assert(vsx_offset <
sizeof(m_vsx_ppc64le));
317 if (vsx_offset <
sizeof(m_vsx_ppc64le) / 2) {
327 ::memcpy(value, reg_value.
GetBytes(), 16);
329 src = (uint8_t *)value;
330 dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
331 ::memcpy(dst, src, 8);
333 dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
334 ::memcpy(dst, src, 8);
344 uint32_t vmx_offset = vsx_offset -
sizeof(m_vsx_ppc64le) / 2;
345 uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
353 return Status(
"failed - register wasn't recognized to be a GPR, FPR, VSX "
354 "or VMX, write strategy unknown");
357Status NativeRegisterContextLinux_ppc64le::ReadAllRegisterValues(
378 uint8_t *dst = data_sp->GetBytes();
379 ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize());
381 ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize());
383 ::memcpy(dst, &m_vmx_ppc64le,
sizeof(m_vmx_ppc64le));
384 dst +=
sizeof(m_vmx_ppc64le);
385 ::memcpy(dst, &m_vsx_ppc64le,
sizeof(m_vsx_ppc64le));
390Status NativeRegisterContextLinux_ppc64le::WriteAllRegisterValues(
395 error.SetErrorStringWithFormat(
396 "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided",
402 error.SetErrorStringWithFormat(
403 "NativeRegisterContextLinux_ppc64le::%s data_sp contained mismatched "
404 "data size, expected %" PRIu64
", actual %" PRIu64,
409 const uint8_t *src = data_sp->GetBytes();
410 if (src ==
nullptr) {
411 error.SetErrorStringWithFormat(
"NativeRegisterContextLinux_ppc64le::%s "
412 "DataBuffer::GetBytes() returned a null "
418 ::memcpy(&m_gpr_ppc64le, src, GetGPRSize());
425 ::memcpy(&m_fpr_ppc64le, src, GetFPRSize());
432 ::memcpy(&m_vmx_ppc64le, src,
sizeof(m_vmx_ppc64le));
438 src +=
sizeof(m_vmx_ppc64le);
439 ::memcpy(&m_vsx_ppc64le, src,
sizeof(m_vsx_ppc64le));
445bool NativeRegisterContextLinux_ppc64le::IsGPR(
unsigned reg)
const {
449bool NativeRegisterContextLinux_ppc64le::IsFPR(
unsigned reg)
const {
453uint32_t NativeRegisterContextLinux_ppc64le::CalculateFprOffset(
459uint32_t NativeRegisterContextLinux_ppc64le::CalculateVmxOffset(
465uint32_t NativeRegisterContextLinux_ppc64le::CalculateVsxOffset(
471Status NativeRegisterContextLinux_ppc64le::ReadVMX() {
472 int regset = NT_PPC_VMX;
473 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(),
474 ®set, &m_vmx_ppc64le,
475 sizeof(m_vmx_ppc64le));
478Status NativeRegisterContextLinux_ppc64le::WriteVMX() {
479 int regset = NT_PPC_VMX;
480 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVRREGS, m_thread.GetID(),
481 ®set, &m_vmx_ppc64le,
482 sizeof(m_vmx_ppc64le));
485Status NativeRegisterContextLinux_ppc64le::ReadVSX() {
486 int regset = NT_PPC_VSX;
487 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(),
488 ®set, &m_vsx_ppc64le,
489 sizeof(m_vsx_ppc64le));
492Status NativeRegisterContextLinux_ppc64le::WriteVSX() {
493 int regset = NT_PPC_VSX;
494 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVSRREGS, m_thread.GetID(),
495 ®set, &m_vsx_ppc64le,
496 sizeof(m_vsx_ppc64le));
499bool NativeRegisterContextLinux_ppc64le::IsVMX(
unsigned reg) {
503bool NativeRegisterContextLinux_ppc64le::IsVSX(
unsigned reg) {
507uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints() {
508 Log *log =
GetLog(POSIXLog::Watchpoints);
516 LLDB_LOG(log,
"{0}", m_max_hwp_supported);
517 return m_max_hwp_supported;
520uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint(
522 Log *log =
GetLog(POSIXLog::Watchpoints);
523 LLDB_LOG(log,
"addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
532 uint32_t control_value = 0, wp_index = 0;
534 uint32_t rw_mode = 0;
538 switch (watch_flags) {
539 case eWatchpointKindWrite:
540 rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE;
543 case eWatchpointKindRead:
544 rw_mode = PPC_BREAKPOINT_TRIGGER_READ;
547 case (eWatchpointKindRead | eWatchpointKindWrite):
548 rw_mode = PPC_BREAKPOINT_TRIGGER_RW;
555 if (size != 1 && size != 2 && size != 4 && size != 8)
563 addr_t begin = llvm::alignDown(addr, 8);
564 addr_t end = llvm::alignTo(addr + size, 8);
565 size = llvm::PowerOf2Ceil(end - begin);
567 addr = addr & (~0x07);
571 control_value = watch_flags << 3;
572 control_value |= ((1 << size) - 1) << 5;
573 control_value |= (2 << 1) | 1;
577 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
578 if ((m_hwp_regs[i].control & 1) == 0) {
580 }
else if (m_hwp_regs[i].address == addr) {
589 m_hwp_regs[wp_index].real_addr = real_addr;
590 m_hwp_regs[wp_index].address = addr;
591 m_hwp_regs[wp_index].control = control_value;
592 m_hwp_regs[wp_index].mode = rw_mode;
595 error = WriteHardwareDebugRegs();
598 m_hwp_regs[wp_index].address = 0;
599 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
607bool NativeRegisterContextLinux_ppc64le::ClearHardwareWatchpoint(
609 Log *log =
GetLog(POSIXLog::Watchpoints);
610 LLDB_LOG(log,
"wp_index: {0}", wp_index);
618 if (wp_index >= m_max_hwp_supported)
623 uint32_t tempControl = m_hwp_regs[wp_index].control;
624 long *tempSlot =
reinterpret_cast<long *
>(m_hwp_regs[wp_index].slot);
627 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
628 m_hwp_regs[wp_index].address = 0;
629 m_hwp_regs[wp_index].slot = 0;
630 m_hwp_regs[wp_index].mode = 0;
633 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_DELHWDEBUG,
634 m_thread.GetID(), 0, tempSlot);
637 m_hwp_regs[wp_index].control = tempControl;
638 m_hwp_regs[wp_index].address = tempAddr;
639 m_hwp_regs[wp_index].slot =
reinterpret_cast<long>(tempSlot);
648NativeRegisterContextLinux_ppc64le::GetWatchpointSize(uint32_t wp_index) {
649 Log *log =
GetLog(POSIXLog::Watchpoints);
650 LLDB_LOG(log,
"wp_index: {0}", wp_index);
652 unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff;
653 if (llvm::isPowerOf2_32(control + 1)) {
654 return llvm::popcount(control);
660bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled(
662 Log *log =
GetLog(POSIXLog::Watchpoints);
663 LLDB_LOG(log,
"wp_index: {0}", wp_index);
665 return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1);
668Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex(
670 Log *log =
GetLog(POSIXLog::Watchpoints);
671 LLDB_LOG(log,
"wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
676 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
677 watch_size = GetWatchpointSize(wp_index);
678 watch_addr = m_hwp_regs[wp_index].address;
680 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
681 trap_addr <= watch_addr + watch_size) {
682 m_hwp_regs[wp_index].hit_addr = trap_addr;
692NativeRegisterContextLinux_ppc64le::GetWatchpointAddress(uint32_t wp_index) {
693 Log *log =
GetLog(POSIXLog::Watchpoints);
694 LLDB_LOG(log,
"wp_index: {0}", wp_index);
696 if (wp_index >= m_max_hwp_supported)
699 if (WatchpointIsEnabled(wp_index))
700 return m_hwp_regs[wp_index].real_addr;
706NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress(uint32_t wp_index) {
707 Log *log =
GetLog(POSIXLog::Watchpoints);
708 LLDB_LOG(log,
"wp_index: {0}", wp_index);
710 if (wp_index >= m_max_hwp_supported)
713 if (WatchpointIsEnabled(wp_index))
714 return m_hwp_regs[wp_index].hit_addr;
719Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo() {
720 if (!m_refresh_hwdebug_info) {
724 ::pid_t tid = m_thread.GetID();
726 struct ppc_debug_info hwdebug_info;
729 error = NativeProcessLinux::PtraceWrapper(
730 PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info,
sizeof(hwdebug_info));
735 m_max_hwp_supported = hwdebug_info.num_data_bps;
736 m_max_hbp_supported = hwdebug_info.num_instruction_bps;
737 m_refresh_hwdebug_info =
false;
742Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs() {
743 struct ppc_hw_breakpoint reg_state;
747 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
748 reg_state.addr = m_hwp_regs[i].address;
749 reg_state.trigger_type = m_hwp_regs[i].mode;
750 reg_state.version = 1;
751 reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
752 reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
754 reg_state.condition_value = 0;
756 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_SETHWDEBUG,
757 m_thread.GetID(), 0, ®_state,
758 sizeof(reg_state), &ret);
763 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.