9#if defined(__loongarch__) && __loongarch_grlen == 64
31#ifndef NT_LOONGARCH_LSX
32#define NT_LOONGARCH_LSX 0xa02
36#ifndef NT_LOONGARCH_LASX
37#define NT_LOONGARCH_LASX 0xa03
41#ifndef NT_LOONGARCH_HW_BREAK
42#define NT_LOONGARCH_HW_BREAK 0xa05
46#ifndef NT_LOONGARCH_HW_WATCH
47#define NT_LOONGARCH_HW_WATCH 0xa06
50#define REG_CONTEXT_SIZE \
51 (GetGPRSize() + GetFPRSize() + sizeof(m_lsx) + sizeof(m_lasx))
60struct loongarch_user_watch_state {
74std::unique_ptr<NativeRegisterContextLinux>
77 switch (target_arch.GetMachine()) {
78 case llvm::Triple::loongarch64: {
80 auto register_info_up = std::make_unique<RegisterInfoPOSIX_loongarch64>(
81 target_arch, opt_regsets);
82 return std::make_unique<NativeRegisterContextLinux_loongarch64>(
83 target_arch, native_thread, std::move(register_info_up));
86 llvm_unreachable(
"have no register context for architecture");
90llvm::Expected<ArchSpec>
92 return HostInfo::GetArchitecture();
95NativeRegisterContextLinux_loongarch64::NativeRegisterContextLinux_loongarch64(
97 std::unique_ptr<RegisterInfoPOSIX_loongarch64> register_info_up)
99 register_info_up.release()),
101 ::memset(&m_fpr, 0,
sizeof(m_fpr));
102 ::memset(&m_gpr, 0,
sizeof(m_gpr));
103 ::memset(&m_lsx, 0,
sizeof(m_lsx));
104 ::memset(&m_lasx, 0,
sizeof(m_lasx));
106 ::memset(&m_hwp_regs, 0,
sizeof(m_hwp_regs));
107 ::memset(&m_hbp_regs, 0,
sizeof(m_hbp_regs));
112 m_max_hwp_supported = 14;
113 m_max_hbp_supported = 14;
114 m_refresh_hwdebug_info =
true;
116 m_gpr_is_valid =
false;
117 m_fpu_is_valid =
false;
118 m_lsx_is_valid =
false;
119 m_lasx_is_valid =
false;
123NativeRegisterContextLinux_loongarch64::GetRegisterInfo()
const {
128uint32_t NativeRegisterContextLinux_loongarch64::GetRegisterSetCount()
const {
132const RegisterSet *NativeRegisterContextLinux_loongarch64::GetRegisterSet(
133 uint32_t set_index)
const {
134 return GetRegisterInfo().GetRegisterSet(set_index);
137uint32_t NativeRegisterContextLinux_loongarch64::GetUserRegisterCount()
const {
139 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
144Status NativeRegisterContextLinux_loongarch64::ReadRegister(
157 "no lldb regnum for %s",
158 reg_info && reg_info->
name ? reg_info->
name :
"<unknown register>");
160 uint8_t *src =
nullptr;
169 assert(offset < GetGPRSize());
170 src = (uint8_t *)GetGPRBuffer() + offset;
172 }
else if (IsFPR(reg)) {
177 offset = CalculateFprOffset(reg_info);
178 assert(offset < GetFPRSize());
179 src = (uint8_t *)GetFPRBuffer() + offset;
180 }
else if (IsLSX(reg)) {
185 offset = CalculateLsxOffset(reg_info);
186 assert(offset <
sizeof(m_lsx));
187 src = (uint8_t *)&m_lsx + offset;
188 }
else if (IsLASX(reg)) {
193 offset = CalculateLasxOffset(reg_info);
194 assert(offset <
sizeof(m_lasx));
195 src = (uint8_t *)&m_lasx + offset;
198 "failed - register wasn't recognized to be a GPR or an FPR, "
199 "write strategy unknown");
207Status NativeRegisterContextLinux_loongarch64::WriteRegister(
218 "no lldb regnum for %s",
219 reg_info->
name !=
nullptr ? reg_info->
name :
"<unknown register>");
221 uint8_t *dst =
nullptr;
230 dst = (uint8_t *)GetGPRBuffer() + reg_info->
byte_offset;
234 }
else if (IsFPR(reg)) {
239 offset = CalculateFprOffset(reg_info);
240 assert(offset < GetFPRSize());
241 dst = (uint8_t *)GetFPRBuffer() + offset;
245 }
else if (IsLSX(reg)) {
250 offset = CalculateLsxOffset(reg_info);
251 assert(offset <
sizeof(m_lsx));
252 dst = (uint8_t *)&m_lsx + offset;
256 }
else if (IsLASX(reg)) {
261 offset = CalculateLasxOffset(reg_info);
262 assert(offset <
sizeof(m_lasx));
263 dst = (uint8_t *)&m_lasx + offset;
272Status NativeRegisterContextLinux_loongarch64::ReadAllRegisterValues(
294 uint8_t *dst = data_sp->GetBytes();
295 ::memcpy(dst, GetGPRBuffer(), GetGPRSize());
297 ::memcpy(dst, GetFPRBuffer(), GetFPRSize());
299 ::memcpy(dst, &m_lsx,
sizeof(m_lsx));
300 dst +=
sizeof(m_lsx);
301 ::memcpy(dst, &m_lasx,
sizeof(m_lasx));
306Status NativeRegisterContextLinux_loongarch64::WriteAllRegisterValues(
312 "NativeRegisterContextLinux_loongarch64::%s invalid data_sp provided",
319 "NativeRegisterContextLinux_loongarch64::%s data_sp contained "
320 "mismatched data size, expected %" PRIu64
", actual %" PRIu64,
325 const uint8_t *src = data_sp->GetBytes();
326 if (src ==
nullptr) {
328 "NativeRegisterContextLinux_loongarch64::%s "
329 "DataBuffer::GetBytes() returned a null "
334 ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize());
340 src += GetRegisterInfoInterface().GetGPRSize();
341 ::memcpy(GetFPRBuffer(), src, GetFPRSize());
342 m_fpu_is_valid =
true;
350 ::memcpy(&m_lsx, src,
sizeof(m_lsx));
351 m_lsx_is_valid =
true;
356 src +=
sizeof(m_lsx);
357 ::memcpy(&m_lasx, src,
sizeof(m_lasx));
358 m_lasx_is_valid =
true;
366bool NativeRegisterContextLinux_loongarch64::IsGPR(
unsigned reg)
const {
367 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
371bool NativeRegisterContextLinux_loongarch64::IsFPR(
unsigned reg)
const {
372 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
376bool NativeRegisterContextLinux_loongarch64::IsLSX(
unsigned reg)
const {
377 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
381bool NativeRegisterContextLinux_loongarch64::IsLASX(
unsigned reg)
const {
382 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
386Status NativeRegisterContextLinux_loongarch64::ReadGPR() {
393 ioVec.iov_base = GetGPRBuffer();
394 ioVec.iov_len = GetGPRSize();
396 error = ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
399 m_gpr_is_valid =
true;
404Status NativeRegisterContextLinux_loongarch64::WriteGPR() {
410 ioVec.iov_base = GetGPRBuffer();
411 ioVec.iov_len = GetGPRSize();
413 m_gpr_is_valid =
false;
415 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
418Status NativeRegisterContextLinux_loongarch64::ReadFPR() {
425 ioVec.iov_base = GetFPRBuffer();
426 ioVec.iov_len = GetFPRSize();
428 error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
431 m_fpu_is_valid =
true;
436Status NativeRegisterContextLinux_loongarch64::WriteFPR() {
442 ioVec.iov_base = GetFPRBuffer();
443 ioVec.iov_len = GetFPRSize();
445 m_fpu_is_valid =
false;
446 m_lsx_is_valid =
false;
447 m_lasx_is_valid =
false;
449 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
452Status NativeRegisterContextLinux_loongarch64::ReadLSX() {
459 ioVec.iov_base = &m_lsx;
460 ioVec.iov_len =
sizeof(m_lsx);
462 error = ReadRegisterSet(&ioVec,
sizeof(m_lsx), NT_LOONGARCH_LSX);
465 m_lsx_is_valid =
true;
470Status NativeRegisterContextLinux_loongarch64::WriteLSX() {
476 ioVec.iov_base = &m_lsx;
477 ioVec.iov_len =
sizeof(m_lsx);
479 m_fpu_is_valid =
false;
480 m_lsx_is_valid =
false;
481 m_lasx_is_valid =
false;
483 return WriteRegisterSet(&ioVec,
sizeof(m_lsx), NT_LOONGARCH_LSX);
486Status NativeRegisterContextLinux_loongarch64::ReadLASX() {
493 ioVec.iov_base = &m_lasx;
494 ioVec.iov_len =
sizeof(m_lasx);
496 error = ReadRegisterSet(&ioVec,
sizeof(m_lasx), NT_LOONGARCH_LASX);
499 m_lasx_is_valid =
true;
504Status NativeRegisterContextLinux_loongarch64::WriteLASX() {
510 ioVec.iov_base = &m_lasx;
511 ioVec.iov_len =
sizeof(m_lasx);
513 m_fpu_is_valid =
false;
514 m_lsx_is_valid =
false;
515 m_lasx_is_valid =
false;
517 return WriteRegisterSet(&ioVec,
sizeof(m_lasx), NT_LOONGARCH_LASX);
520void NativeRegisterContextLinux_loongarch64::InvalidateAllRegisters() {
521 m_gpr_is_valid =
false;
522 m_fpu_is_valid =
false;
523 m_lsx_is_valid =
false;
524 m_lasx_is_valid =
false;
527uint32_t NativeRegisterContextLinux_loongarch64::CalculateFprOffset(
532uint32_t NativeRegisterContextLinux_loongarch64::CalculateLsxOffset(
534 return reg_info->
byte_offset - GetGPRSize() -
sizeof(m_fpr);
537uint32_t NativeRegisterContextLinux_loongarch64::CalculateLasxOffset(
539 return reg_info->
byte_offset - GetGPRSize() -
sizeof(m_fpr) -
sizeof(m_lsx);
543NativeRegisterContextLinux_loongarch64::GetExpeditedRegisters(
545 std::vector<uint32_t> expedited_reg_nums =
548 return expedited_reg_nums;
551llvm::Error NativeRegisterContextLinux_loongarch64::ReadHardwareDebugInfo() {
552 if (!m_refresh_hwdebug_info)
553 return llvm::Error::success();
555 ::pid_t tid = m_thread.GetID();
557 int regset = NT_LOONGARCH_HW_WATCH;
559 struct loongarch_user_watch_state dreg_state;
562 ioVec.iov_base = &dreg_state;
563 ioVec.iov_len =
sizeof(dreg_state);
565 &ioVec, ioVec.iov_len);
567 return error.ToError();
569 m_max_hwp_supported = dreg_state.dbg_info & 0x3f;
571 regset = NT_LOONGARCH_HW_BREAK;
573 &ioVec, ioVec.iov_len);
575 return error.ToError();
577 m_max_hbp_supported = dreg_state.dbg_info & 0x3f;
579 m_refresh_hwdebug_info =
false;
581 return llvm::Error::success();
584llvm::Error NativeRegisterContextLinux_loongarch64::WriteHardwareDebugRegs(
587 struct loongarch_user_watch_state dreg_state;
590 memset(&dreg_state, 0,
sizeof(dreg_state));
591 ioVec.iov_base = &dreg_state;
595 regset = NT_LOONGARCH_HW_WATCH;
596 ioVec.iov_len =
sizeof(dreg_state.dbg_info) +
597 (
sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
599 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
600 dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
601 dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
605 regset = NT_LOONGARCH_HW_BREAK;
606 ioVec.iov_len =
sizeof(dreg_state.dbg_info) +
607 (
sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
609 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
610 dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address;
611 dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control;
617 ®set, &ioVec, ioVec.iov_len)
static llvm::raw_ostream & error(Stream &strm)
size_t GetRegisterSetCount() const override
A subclass of DataBuffer that stores a data buffer on the heap.
const RegisterInfoInterface & GetRegisterInfoInterface() const
virtual std::vector< uint32_t > GetExpeditedRegisters(ExpeditedRegs expType) const
uint32_t SetFromMemoryData(const RegisterInfo ®_info, const void *src, uint32_t src_len, lldb::ByteOrder src_byte_order, Status &error)
const void * GetBytes() const
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
static Status FromErrorString(const char *str)
static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr=nullptr, void *data=nullptr, size_t data_size=0, long *result=nullptr)
}
static std::unique_ptr< NativeRegisterContextLinux > CreateHostNativeRegisterContextLinux(const ArchSpec &target_arch, NativeThreadLinux &native_thread)
static llvm::Expected< ArchSpec > DetermineArchitecture(lldb::tid_t tid)
#define LLDB_INVALID_INDEX32
#define LLDB_INVALID_REGNUM
A class that represents a running process on the host machine.
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.
size_t num_registers
The number of registers in REGISTERS array below.