diff --git a/src/coreclr/debug/di/riscv64/cordbregisterset.cpp b/src/coreclr/debug/di/riscv64/cordbregisterset.cpp index abda3421346d98..469e8fe21359db 100644 --- a/src/coreclr/debug/di/riscv64/cordbregisterset.cpp +++ b/src/coreclr/debug/di/riscv64/cordbregisterset.cpp @@ -83,10 +83,134 @@ HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG64* pAvailable) return S_OK; } +// Reads the value of a single register (identified by a CorDebugRegister index) into *pValue. +// Shared by both GetRegisters overloads to avoid duplicating the per-register mapping. +static HRESULT GetRegisterValue(CordbThread * pThread, const DT_CONTEXT * pContext, int regIndex, CORDB_REGISTER * pValue) +{ + if ((regIndex >= REGISTER_RISCV64_F0) && (regIndex <= REGISTER_RISCV64_F31)) + { + if (!pThread->m_fFloatStateValid) + { + HRESULT hr = S_OK; + EX_TRY + { + pThread->LoadFloatState(); + } + EX_CATCH_HRESULT(hr); + + if ( !SUCCEEDED(hr) ) + { + return hr; + } + LOG( ( LF_CORDB, LL_INFO1000, "CRS::GR: Loaded float state\n" ) ); + } + + *pValue = *(CORDB_REGISTER*)&(pThread->m_floatValues[(regIndex - REGISTER_RISCV64_F0)]); + return S_OK; + } + + switch (regIndex) + { + case REGISTER_RISCV64_PC: + *pValue = pContext->Pc; break; + case REGISTER_RISCV64_RA: + *pValue = pContext->Ra; break; + case REGISTER_RISCV64_SP: + *pValue = pContext->Sp; break; + case REGISTER_RISCV64_GP: + *pValue = pContext->Gp; break; + case REGISTER_RISCV64_TP: + *pValue = pContext->Tp; break; + case REGISTER_RISCV64_T0: + *pValue = pContext->T0; break; + case REGISTER_RISCV64_T1: + *pValue = pContext->T1; break; + case REGISTER_RISCV64_T2: + *pValue = pContext->T2; break; + case REGISTER_RISCV64_FP: + *pValue = pContext->Fp; break; + case REGISTER_RISCV64_S1: + *pValue = pContext->S1; break; + case REGISTER_RISCV64_A0: + *pValue = pContext->A0; break; + case REGISTER_RISCV64_A1: + *pValue = pContext->A1; break; + case REGISTER_RISCV64_A2: + *pValue = pContext->A2; break; + case REGISTER_RISCV64_A3: + *pValue = pContext->A3; break; + case REGISTER_RISCV64_A4: + *pValue = pContext->A4; break; + case REGISTER_RISCV64_A5: + *pValue = pContext->A5; break; + case REGISTER_RISCV64_A6: + *pValue = pContext->A6; break; + case REGISTER_RISCV64_A7: + *pValue = pContext->A7; break; + case REGISTER_RISCV64_S2: + *pValue = pContext->S2; break; + case REGISTER_RISCV64_S3: + *pValue = pContext->S3; break; + case REGISTER_RISCV64_S4: + *pValue = pContext->S4; break; + case REGISTER_RISCV64_S5: + *pValue = pContext->S5; break; + case REGISTER_RISCV64_S6: + *pValue = pContext->S6; break; + case REGISTER_RISCV64_S7: + *pValue = pContext->S7; break; + case REGISTER_RISCV64_S8: + *pValue = pContext->S8; break; + case REGISTER_RISCV64_S9: + *pValue = pContext->S9; break; + case REGISTER_RISCV64_S10: + *pValue = pContext->S10; break; + case REGISTER_RISCV64_S11: + *pValue = pContext->S11; break; + case REGISTER_RISCV64_T3: + *pValue = pContext->T3; break; + case REGISTER_RISCV64_T4: + *pValue = pContext->T4; break; + case REGISTER_RISCV64_T5: + *pValue = pContext->T5; break; + case REGISTER_RISCV64_T6: + *pValue = pContext->T6; break; + default: + _ASSERTE(false); break; + } + + return S_OK; +} + HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, CORDB_REGISTER regBuffer[]) { - _ASSERTE(!"RISCV64:NYI"); + PUBLIC_REENTRANT_API_ENTRY(this); + FAIL_IF_NEUTERED(this); + ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); + + UINT iRegister = 0; + + VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); + + for (int i = REGISTER_RISCV64_PC; + i <= REGISTER_RISCV64_F31 && iRegister < regCount; + i++) + { + if (mask & SETBITULONG64(i)) + { + _ASSERTE (iRegister < regCount); + + HRESULT hr = GetRegisterValue(m_thread, &m_context, i, ®Buffer[iRegister]); + if (FAILED(hr)) + { + return hr; + } + iRegister++; + } + } + + _ASSERTE (iRegister <= regCount); return S_OK; } @@ -94,7 +218,21 @@ HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG32 regCount, BYTE pAvailable[]) { - _ASSERTE(!"RISCV64:NYI"); + FAIL_IF_NEUTERED(this); + VALIDATE_POINTER_TO_OBJECT_ARRAY(pAvailable, CORDB_REGISTER, regCount, true, true); + + for (int i = 0 ; i < (int)regCount ; ++i) + { + if (i * 8 <= REGISTER_RISCV64_F31) + { + pAvailable[i] = (i * 8 == REGISTER_RISCV64_F31) ? BYTE(0x1) : BYTE(0xff); + } + else + { + pAvailable[i] = 0; + } + } + return S_OK; } @@ -102,6 +240,30 @@ HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG32 regCount, HRESULT CordbRegisterSet::GetRegisters(ULONG32 maskCount, BYTE mask[], ULONG32 regCount, CORDB_REGISTER regBuffer[]) { - _ASSERTE(!"RISCV64:NYI"); + FAIL_IF_NEUTERED(this); + VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); + + UINT iRegister = 0; + + for (int m = 0 ; m < (int)maskCount ; ++m) + { + for (int bit = 0 ; bit < 8 ; ++bit) + { + if (mask[m] & SETBITULONG64(bit)) + { + _ASSERTE (iRegister < regCount); + + int i = m * 8 + bit; + + HRESULT hr = GetRegisterValue(m_thread, &m_context, i, ®Buffer[iRegister]); + if (FAILED(hr)) + { + return hr; + } + iRegister++; + } + } + } + return S_OK; } diff --git a/src/coreclr/debug/di/rspriv.h b/src/coreclr/debug/di/rspriv.h index ace851825d6721..c790b75d8fdef4 100644 --- a/src/coreclr/debug/di/rspriv.h +++ b/src/coreclr/debug/di/rspriv.h @@ -6084,6 +6084,10 @@ class CordbThread : public CordbBase, public ICorDebugThread, // Converts the values in the floating point register area of the context to real number values. void Get64bitFPRegisters(FPRegister64 * rgContextFPRegisters, int start, int nRegisters); +#elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) + // Copies the scalar 64-bit IEEE-754 value of each floating point register from the context. + void GetRawFPRegisters(ULONGLONG * pFPRegisters, int slotsPerRegister, int nRegisters); + #endif // TARGET_X86 // Initializes the float state members of this instance of CordbThread. This function gets the context and diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index d2d4cf5b25518c..8d68557f538bff 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -1546,6 +1546,28 @@ void CordbThread::Get64bitFPRegisters(FPRegister64 * rgContextFPRegisters, int s } } // CordbThread::Get64bitFPRegisters +#elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) + +// CordbThread::GetRawFPRegisters +// Copies the scalar 64-bit IEEE-754 value of each floating point register directly from the +// context. On these platforms the floating point registers are already stored as raw doubles, so +// no hardware conversion (FPFillR8) is needed. slotsPerRegister is the number of ULONGLONG slots +// each register occupies in the context: 1 for RISC-V64, and 4 for LoongArch64, whose FPR64/LSX/LASX +// layout stores the scalar value in the first 64-bit slot of each group. +// Arguments: +// input: pFPRegisters - starting address of the floating point register storage of the CONTEXT +// slotsPerRegister - the number of ULONGLONG slots each register occupies +// nRegisters - the number of registers to be initialized +// output: none (initializes m_floatValues) + +void CordbThread::GetRawFPRegisters(ULONGLONG * pFPRegisters, int slotsPerRegister, int nRegisters) +{ + for (int reg = 0; reg < nRegisters; reg++) + { + m_floatValues[reg] = *(double*)&(pFPRegisters[reg * slotsPerRegister]); + } +} // CordbThread::GetRawFPRegisters + #endif // TARGET_X86 // CordbThread::LoadFloatState @@ -1580,6 +1602,13 @@ void CordbThread::LoadFloatState() Get64bitFPRegisters((FPRegister64*) &(tempContext.V), 0, 32); #elif defined (TARGET_ARM) Get64bitFPRegisters((FPRegister64*) &(tempContext.D), 0, 32); +#elif defined(TARGET_RISCV64) + // RISC-V64 stores each F register as a single raw 64-bit IEEE-754 value in the context. + GetRawFPRegisters((ULONGLONG*) &(tempContext.F), 1, DebuggerIPCE_FloatCount); +#elif defined(TARGET_LOONGARCH64) + // LoongArch64 stores floating point registers in a SIMD-capable layout (FPR64/LSX/LASX), where + // each F register occupies 4 ULONGLONG slots and the scalar value is the first 64-bit slot. + GetRawFPRegisters((ULONGLONG*) &(tempContext.F), 4, DebuggerIPCE_FloatCount); #else _ASSERTE(!"nyi for platform"); #endif // !TARGET_X86